# HG changeset patch # User ccheung # Date 1429306640 25200 # Node ID 5c6dacbd17ae9ef1aead2563e3beb1354c634fe3 # Parent 9925b07bba5b43d3de5d783d1cb91dcc9533f842# Parent fdb68fee3e4197fe2c225272ddf84f0ebf2af1b3 Merge diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Fri Apr 17 14:37:20 2015 -0700 @@ -29,9 +29,9 @@ import java.util.Observer; import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.gc_interface.CollectedHeap; import sun.jvm.hotspot.gc_interface.CollectedHeapName; import sun.jvm.hotspot.memory.MemRegion; -import sun.jvm.hotspot.memory.SharedHeap; import sun.jvm.hotspot.memory.SpaceClosure; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.VMObjectFactory; @@ -41,7 +41,7 @@ // Mirror class for G1CollectedHeap. -public class G1CollectedHeap extends SharedHeap { +public class G1CollectedHeap extends CollectedHeap { // HeapRegionManager _hrm; static private long hrmFieldOffset; // MemRegion _g1_reserved; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; -public class CollectedHeap extends VMObject { +public abstract class CollectedHeap extends VMObject { private static long reservedFieldOffset; static { @@ -73,9 +73,7 @@ return reservedRegion().contains(a); } - public CollectedHeapName kind() { - return CollectedHeapName.ABSTRACT; - } + public abstract CollectedHeapName kind(); public void print() { printOn(System.out); } public void printOn(PrintStream tty) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,6 @@ private CollectedHeapName(String name) { this.name = name; } - public static final CollectedHeapName ABSTRACT = new CollectedHeapName("abstract"); - public static final CollectedHeapName SHARED_HEAP = new CollectedHeapName("SharedHeap"); public static final CollectedHeapName GEN_COLLECTED_HEAP = new CollectedHeapName("GenCollectedHeap"); public static final CollectedHeapName G1_COLLECTED_HEAP = new CollectedHeapName("G1CollectedHeap"); public static final CollectedHeapName PARALLEL_SCAVENGE_HEAP = new CollectedHeapName("ParallelScavengeHeap"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java Fri Apr 17 14:37:20 2015 -0700 @@ -33,8 +33,7 @@ import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; -public class GenCollectedHeap extends SharedHeap { - private static CIntegerField nGensField; +public class GenCollectedHeap extends CollectedHeap { private static AddressField youngGenField; private static AddressField oldGenField; @@ -54,7 +53,6 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("GenCollectedHeap"); - nGensField = type.getCIntegerField("_n_gens"); youngGenField = type.getAddressField("_young_gen"); oldGenField = type.getAddressField("_old_gen"); @@ -70,7 +68,7 @@ } public int nGens() { - return (int) nGensField.getValue(addr); + return 2; // Young + Old } public Generation getGen(int i) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SharedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SharedHeap.java Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package sun.jvm.hotspot.memory; - -import java.io.*; -import java.util.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.gc_interface.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; - -public abstract class SharedHeap extends CollectedHeap { - private static VirtualConstructor ctor; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("SharedHeap"); - ctor = new VirtualConstructor(db); - } - - public SharedHeap(Address addr) { - super(addr); - } - - public CollectedHeapName kind() { - return CollectedHeapName.SHARED_HEAP; - } - } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,11 +112,7 @@ return ""; } public CollectedHeap heap() { - try { - return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue()); - } catch (WrongTypeException e) { - return new CollectedHeap(collectedHeapField.getValue()); - } + return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue()); } public static long getNarrowOopBase() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Fri Apr 17 14:37:20 2015 -0700 @@ -81,53 +81,48 @@ System.out.println(); System.out.println("Heap Usage:"); - if (heap instanceof SharedHeap) { - SharedHeap sharedHeap = (SharedHeap) heap; - if (sharedHeap instanceof GenCollectedHeap) { - GenCollectedHeap genHeap = (GenCollectedHeap) sharedHeap; - for (int n = 0; n < genHeap.nGens(); n++) { - Generation gen = genHeap.getGen(n); - if (gen instanceof sun.jvm.hotspot.memory.DefNewGeneration) { - System.out.println("New Generation (Eden + 1 Survivor Space):"); - printGen(gen); + if (heap instanceof GenCollectedHeap) { + GenCollectedHeap genHeap = (GenCollectedHeap) heap; + for (int n = 0; n < genHeap.nGens(); n++) { + Generation gen = genHeap.getGen(n); + if (gen instanceof sun.jvm.hotspot.memory.DefNewGeneration) { + System.out.println("New Generation (Eden + 1 Survivor Space):"); + printGen(gen); - ContiguousSpace eden = ((DefNewGeneration)gen).eden(); - System.out.println("Eden Space:"); - printSpace(eden); + ContiguousSpace eden = ((DefNewGeneration)gen).eden(); + System.out.println("Eden Space:"); + printSpace(eden); - ContiguousSpace from = ((DefNewGeneration)gen).from(); - System.out.println("From Space:"); - printSpace(from); + ContiguousSpace from = ((DefNewGeneration)gen).from(); + System.out.println("From Space:"); + printSpace(from); - ContiguousSpace to = ((DefNewGeneration)gen).to(); - System.out.println("To Space:"); - printSpace(to); - } else { - System.out.println(gen.name() + ":"); - printGen(gen); - } + ContiguousSpace to = ((DefNewGeneration)gen).to(); + System.out.println("To Space:"); + printSpace(to); + } else { + System.out.println(gen.name() + ":"); + printGen(gen); } - } else if (sharedHeap instanceof G1CollectedHeap) { - G1CollectedHeap g1h = (G1CollectedHeap) sharedHeap; - G1MonitoringSupport g1mm = g1h.g1mm(); - long edenRegionNum = g1mm.edenRegionNum(); - long survivorRegionNum = g1mm.survivorRegionNum(); - HeapRegionSetBase oldSet = g1h.oldSet(); - HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldRegionNum = oldSet.count().length() - + humongousSet.count().capacity() / HeapRegion.grainBytes(); - printG1Space("G1 Heap:", g1h.n_regions(), - g1h.used(), g1h.capacity()); - System.out.println("G1 Young Generation:"); - printG1Space("Eden Space:", edenRegionNum, - g1mm.edenUsed(), g1mm.edenCommitted()); - printG1Space("Survivor Space:", survivorRegionNum, - g1mm.survivorUsed(), g1mm.survivorCommitted()); - printG1Space("G1 Old Generation:", oldRegionNum, - g1mm.oldUsed(), g1mm.oldCommitted()); - } else { - throw new RuntimeException("unknown SharedHeap type : " + heap.getClass()); } + } else if (heap instanceof G1CollectedHeap) { + G1CollectedHeap g1h = (G1CollectedHeap) heap; + G1MonitoringSupport g1mm = g1h.g1mm(); + long edenRegionNum = g1mm.edenRegionNum(); + long survivorRegionNum = g1mm.survivorRegionNum(); + HeapRegionSetBase oldSet = g1h.oldSet(); + HeapRegionSetBase humongousSet = g1h.humongousSet(); + long oldRegionNum = oldSet.count().length() + + humongousSet.count().capacity() / HeapRegion.grainBytes(); + printG1Space("G1 Heap:", g1h.n_regions(), + g1h.used(), g1h.capacity()); + System.out.println("G1 Young Generation:"); + printG1Space("Eden Space:", edenRegionNum, + g1mm.edenUsed(), g1mm.edenCommitted()); + printG1Space("Survivor Space:", survivorRegionNum, + g1mm.survivorUsed(), g1mm.survivorCommitted()); + printG1Space("G1 Old Generation:", oldRegionNum, + g1mm.oldUsed(), g1mm.oldCommitted()); } else if (heap instanceof ParallelScavengeHeap) { ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; PSYoungGen youngGen = psh.youngGen(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/aix/makefiles/adlc.make --- a/hotspot/make/aix/makefiles/adlc.make Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/aix/makefiles/adlc.make Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -140,13 +140,7 @@ # Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. ADLCFLAGS += -q -T -# Normally, debugging is done directly on the ad_*.cpp files. -# But -g will put #line directives in those files pointing back to .ad. -# Some builds of gcc 3.2 have a bug that gets tickled by the extra #line directives -# so skip it for 3.2 and ealier. -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" ADLCFLAGS += -g -endif ifdef LP64 ADLCFLAGS += -D_LP64 diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/aix/makefiles/mapfile-vers-debug --- a/hotspot/make/aix/makefiles/mapfile-vers-debug Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/aix/makefiles/mapfile-vers-debug Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/aix/makefiles/mapfile-vers-product --- a/hotspot/make/aix/makefiles/mapfile-vers-product Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/aix/makefiles/mapfile-vers-product Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetInheritedAccessControlContext; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/aix/makefiles/ppc64.make --- a/hotspot/make/aix/makefiles/ppc64.make Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/aix/makefiles/ppc64.make Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ # -# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. +# Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, 2015 SAP AG. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -71,9 +71,6 @@ OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/sharedRuntimeTrans.o = $(OPT_CFLAGS/NOOPT) -# xlc 10.01 parameters for ipa compile. -QIPA_COMPILE=$(if $(CXX_IS_V10),-qipa) - # Xlc 10.1 parameters for aggressive optimization: # - qhot=level=1: Most aggressive loop optimizations. # - qignerrno: Assume errno is not modified by system calls. @@ -88,7 +85,7 @@ OPT_CFLAGS/synchronizer.o = $(OPT_CFLAGS) -qnoinline # Set all the xlC V10.1 options here. -OPT_CFLAGS += $(QIPA_COMPILE) $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) +OPT_CFLAGS += $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) export OBJECT_MODE=64 diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/aix/makefiles/xlc.make --- a/hotspot/make/aix/makefiles/xlc.make Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/aix/makefiles/xlc.make Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2012, 2013 SAP. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2015 SAP. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -34,13 +34,17 @@ AS = $(CC) -c -# get xlc version -CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | sed -n 's/.*Version: \([0-9.]*\)/\1/p') +# get xlc version which comes as VV.RR.MMMM.LLLL where 'VV' is the version, +# 'RR' is the release, 'MMMM' is the modification and 'LLLL' is the level. +# We only use 'VV.RR.LLLL' to avoid integer overflows in bash when comparing +# the version numbers (some shells only support 32-bit integer compares!). +CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | \ + sed -n 's/.*Version: \([0-9]\{2\}\).\([0-9]\{2\}\).[0-9]\{4\}.\([0-9]\{4\}\)/\1\2\3/p') # xlc 08.00.0000.0023 and higher supports -qtune=balanced -CXX_SUPPORTS_BALANCED_TUNING=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 080000000023 ] ; then echo "true" ; fi) +CXX_SUPPORTS_BALANCED_TUNING := $(shell if [ $(CXX_VERSION) -ge 08000023 ] ; then echo "true" ; fi) # xlc 10.01 is used with aggressive optimizations to boost performance -CXX_IS_V10=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 100100000000 ] ; then echo "true" ; fi) +CXX_IS_V10 := $(shell if [ $(CXX_VERSION) -ge 10010000 ] ; then echo "true" ; fi) # check for precompiled headers support diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug Fri Apr 17 14:37:20 2015 -0700 @@ -105,6 +105,7 @@ _JVM_GetClassTypeAnnotations _JVM_GetDeclaredClasses _JVM_GetDeclaringClass + _JVM_GetSimpleBinaryName _JVM_GetEnclosingMethodInfo _JVM_GetFieldIxModifiers _JVM_GetFieldTypeAnnotations diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/bsd/makefiles/mapfile-vers-darwin-product --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product Fri Apr 17 14:37:20 2015 -0700 @@ -105,6 +105,7 @@ _JVM_GetClassTypeAnnotations _JVM_GetDeclaredClasses _JVM_GetDeclaringClass + _JVM_GetSimpleBinaryName _JVM_GetEnclosingMethodInfo _JVM_GetFieldIxModifiers _JVM_GetFieldTypeAnnotations diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/bsd/makefiles/mapfile-vers-debug --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/bsd/makefiles/mapfile-vers-product --- a/hotspot/make/bsd/makefiles/mapfile-vers-product Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/build.sh --- a/hotspot/make/build.sh Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/build.sh Fri Apr 17 14:37:20 2015 -0700 @@ -40,7 +40,7 @@ exit 1 fi -if [ "${JAVA_HOME-}" = "" -o ! -d "${JAVA_HOME-}" -o ! -d ${JAVA_HOME-}/jre/lib/ ]; then +if [ "${JAVA_HOME-}" = "" -o ! -d "${JAVA_HOME-}" ]; then echo "JAVA_HOME needs to be set to a valid JDK path" echo "JAVA_HOME: ${JAVA_HOME-}" exit 1 diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/linux/makefiles/mapfile-vers-debug --- a/hotspot/make/linux/makefiles/mapfile-vers-debug Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/linux/makefiles/mapfile-vers-product --- a/hotspot/make/linux/makefiles/mapfile-vers-product Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/linux/makefiles/mapfile-vers-product Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/solaris/makefiles/mapfile-vers --- a/hotspot/make/solaris/makefiles/mapfile-vers Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/solaris/makefiles/mapfile-vers Fri Apr 17 14:37:20 2015 -0700 @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Define public interface. @@ -30,7 +30,7 @@ JNI_CreateJavaVM; JNI_GetCreatedJavaVMs; JNI_GetDefaultJavaVMInitArgs; - + # JVM JVM_ActiveProcessorCount; JVM_ArrayCopy; @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/make/solaris/makefiles/product.make --- a/hotspot/make/solaris/makefiles/product.make Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/make/solaris/makefiles/product.make Fri Apr 17 14:37:20 2015 -0700 @@ -37,6 +37,11 @@ OPT_CFLAGS/ciEnv.o = $(OPT_CFLAGS) -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_ endif +# Need extra inlining to get oop_ps_push_contents functions to perform well enough. +ifndef USE_GCC +OPT_CFLAGS/psPromotionManager.o = $(OPT_CFLAGS) -W2,-Ainline:inc=1000 +endif + # (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files) ifeq ("${Platform_compiler}", "sparcWorks") diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Apr 17 14:37:20 2015 -0700 @@ -1818,6 +1818,8 @@ case INDINDEXSCALEDI2L: case INDINDEXSCALEDOFFSETI2LN: case INDINDEXSCALEDI2LN: + case INDINDEXOFFSETI2L: + case INDINDEXOFFSETI2LN: scale = Address::sxtw(size); break; default: @@ -4264,6 +4266,20 @@ %} %} +operand indIndexOffsetI2L(iRegP reg, iRegI ireg, immLU12 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP reg (ConvI2L ireg)) off); + op_cost(INSN_COST); + format %{ "$reg, $ireg, $off I2L" %} + interface(MEMORY_INTER) %{ + base($reg); + index($ireg); + scale(0x0); + disp($off); + %} +%} + operand indIndexScaledOffsetI2L(iRegP reg, iRegI ireg, immIScale scale, immLU12 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); @@ -4324,7 +4340,7 @@ %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); - op_cost(INSN_COST); + op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); @@ -4394,6 +4410,21 @@ %} %} +operand indIndexOffsetI2LN(iRegN reg, iRegI ireg, immLU12 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) (ConvI2L ireg)) off); + op_cost(INSN_COST); + format %{ "$reg, $ireg, $off I2L\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index($ireg); + scale(0x0); + disp($off); + %} +%} + operand indIndexScaledOffsetI2LN(iRegN reg, iRegI ireg, immIScale scale, immLU12 off) %{ predicate(Universe::narrow_oop_shift() == 0); @@ -4656,8 +4687,8 @@ // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory(indirect, indIndexScaledOffsetI, indIndexScaledOffsetL, indIndexScaledOffsetI2L, indIndexScaled, indIndexScaledI2L, indIndex, indOffI, indOffL, - indirectN, indIndexScaledOffsetIN, indIndexScaledOffsetLN, indIndexScaledOffsetI2LN, indIndexScaledN, indIndexScaledI2LN, indIndexN, indOffIN, indOffLN); +opclass memory(indirect, indIndexScaledOffsetI, indIndexScaledOffsetL, indIndexOffsetI2L, indIndexScaledOffsetI2L, indIndexScaled, indIndexScaledI2L, indIndex, indOffI, indOffL, + indirectN, indIndexScaledOffsetIN, indIndexScaledOffsetLN, indIndexOffsetI2LN, indIndexScaledOffsetI2LN, indIndexScaledN, indIndexScaledI2LN, indIndexN, indOffIN, indOffLN); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) @@ -7523,7 +7554,7 @@ instruct addP_reg_reg_ext(iRegPNoSp dst, iRegP src1, iRegIorL2I src2) %{ match(Set dst (AddP src1 (ConvI2L src2))); - ins_cost(INSN_COST); + ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtw\t# ptr" %} ins_encode %{ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1469,7 +1469,7 @@ f(op, 31, 29); f(0b11010000, 28, 21); f(0b000000, 15, 10); - rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); + zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); } #define INSN(NAME, op) \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ protected: // Interpreter specific version of call_VM_base + using MacroAssembler::call_VM_leaf_base; + virtual void call_VM_leaf_base(address entry_point, int number_of_arguments); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2246,6 +2246,341 @@ } /** + * Helpers for multiply_to_len(). + */ +void MacroAssembler::add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2) { + adds(dest_lo, dest_lo, src1); + adc(dest_hi, dest_hi, zr); + adds(dest_lo, dest_lo, src2); + adc(final_dest_hi, dest_hi, zr); +} + +// Generate an address from (r + r1 extend offset). "size" is the +// size of the operand. The result may be in rscratch2. +Address MacroAssembler::offsetted_address(Register r, Register r1, + Address::extend ext, int offset, int size) { + if (offset || (ext.shift() % size != 0)) { + lea(rscratch2, Address(r, r1, ext)); + return Address(rscratch2, offset); + } else { + return Address(r, r1, ext); + } +} + +/** + * Multiply 64 bit by 64 bit first loop. + */ +void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) { + // + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // huge_128 product = y[idx] * x[xstart] + carry; + // z[kdx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // z[xstart] = carry; + // + + Label L_first_loop, L_first_loop_exit; + Label L_one_x, L_one_y, L_multiply; + + subsw(xstart, xstart, 1); + br(Assembler::MI, L_one_x); + + lea(rscratch1, Address(x, xstart, Address::lsl(LogBytesPerInt))); + ldr(x_xstart, Address(rscratch1)); + ror(x_xstart, x_xstart, 32); // convert big-endian to little-endian + + bind(L_first_loop); + subsw(idx, idx, 1); + br(Assembler::MI, L_first_loop_exit); + subsw(idx, idx, 1); + br(Assembler::MI, L_one_y); + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + ldr(y_idx, Address(rscratch1)); + ror(y_idx, y_idx, 32); // convert big-endian to little-endian + bind(L_multiply); + + // AArch64 has a multiply-accumulate instruction that we can't use + // here because it has no way to process carries, so we have to use + // separate add and adc instructions. Bah. + umulh(rscratch1, x_xstart, y_idx); // x_xstart * y_idx -> rscratch1:product + mul(product, x_xstart, y_idx); + adds(product, product, carry); + adc(carry, rscratch1, zr); // x_xstart * y_idx + carry -> carry:product + + subw(kdx, kdx, 2); + ror(product, product, 32); // back to big-endian + str(product, offsetted_address(z, kdx, Address::uxtw(LogBytesPerInt), 0, BytesPerLong)); + + b(L_first_loop); + + bind(L_one_y); + ldrw(y_idx, Address(y, 0)); + b(L_multiply); + + bind(L_one_x); + ldrw(x_xstart, Address(x, 0)); + b(L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 128 bit by 128. Unrolled inner loop. + * + */ +void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp6, Register product_hi) { + + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 tmp3 = (y[idx+1] * product_hi) + z[kdx+idx+1] + carry; + // jlong carry2 = (jlong)(tmp3 >>> 64); + // huge_128 tmp4 = (y[idx] * product_hi) + z[kdx+idx] + carry2; + // carry = (jlong)(tmp4 >>> 64); + // z[kdx+idx+1] = (jlong)tmp3; + // z[kdx+idx] = (jlong)tmp4; + // } + // idx += 2; + // if (idx > 0) { + // yz_idx1 = (y[idx] * product_hi) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)yz_idx1; + // carry = (jlong)(yz_idx1 >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + lsrw(jdx, idx, 2); + + bind(L_third_loop); + + subsw(jdx, jdx, 1); + br(Assembler::MI, L_third_loop_exit); + subw(idx, idx, 4); + + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + + ldp(yz_idx2, yz_idx1, Address(rscratch1, 0)); + + lea(tmp6, Address(z, idx, Address::uxtw(LogBytesPerInt))); + + ror(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian + ror(yz_idx2, yz_idx2, 32); + + ldp(rscratch2, rscratch1, Address(tmp6, 0)); + + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + umulh(tmp4, product_hi, yz_idx1); + + ror(rscratch1, rscratch1, 32); // convert big-endian to little-endian + ror(rscratch2, rscratch2, 32); + + mul(tmp, product_hi, yz_idx2); // yz_idx2 * product_hi -> carry2:tmp + umulh(carry2, product_hi, yz_idx2); + + // propagate sum of both multiplications into carry:tmp4:tmp3 + adds(tmp3, tmp3, carry); + adc(tmp4, tmp4, zr); + adds(tmp3, tmp3, rscratch1); + adcs(tmp4, tmp4, tmp); + adc(carry, carry2, zr); + adds(tmp4, tmp4, rscratch2); + adc(carry, carry, zr); + + ror(tmp3, tmp3, 32); // convert little-endian to big-endian + ror(tmp4, tmp4, 32); + stp(tmp4, tmp3, Address(tmp6, 0)); + + b(L_third_loop); + bind (L_third_loop_exit); + + andw (idx, idx, 0x3); + cbz(idx, L_post_third_loop_done); + + Label L_check_1; + subsw(idx, idx, 2); + br(Assembler::MI, L_check_1); + + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + ldr(yz_idx1, Address(rscratch1, 0)); + ror(yz_idx1, yz_idx1, 32); + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + umulh(tmp4, product_hi, yz_idx1); + lea(rscratch1, Address(z, idx, Address::uxtw(LogBytesPerInt))); + ldr(yz_idx2, Address(rscratch1, 0)); + ror(yz_idx2, yz_idx2, 32); + + add2_with_carry(carry, tmp4, tmp3, carry, yz_idx2); + + ror(tmp3, tmp3, 32); + str(tmp3, Address(rscratch1, 0)); + + bind (L_check_1); + + andw (idx, idx, 0x1); + subsw(idx, idx, 1); + br(Assembler::MI, L_post_third_loop_done); + ldrw(tmp4, Address(y, idx, Address::uxtw(LogBytesPerInt))); + mul(tmp3, tmp4, product_hi); // tmp4 * product_hi -> carry2:tmp3 + umulh(carry2, tmp4, product_hi); + ldrw(tmp4, Address(z, idx, Address::uxtw(LogBytesPerInt))); + + add2_with_carry(carry2, tmp3, tmp4, carry); + + strw(tmp3, Address(z, idx, Address::uxtw(LogBytesPerInt))); + extr(carry, carry2, tmp3, 32); + + bind(L_post_third_loop_done); +} + +/** + * Code for BigInteger::multiplyToLen() instrinsic. + * + * r0: x + * r1: xlen + * r2: y + * r3: ylen + * r4: z + * r5: zlen + * r10: tmp1 + * r11: tmp2 + * r12: tmp3 + * r13: tmp4 + * r14: tmp5 + * r15: tmp6 + * r16: tmp7 + * + */ +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, + Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, + Register tmp5, Register tmp6, Register product_hi) { + + assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + const Register idx = tmp1; + const Register kdx = tmp2; + const Register xstart = tmp3; + + const Register y_idx = tmp4; + const Register carry = tmp5; + const Register product = xlen; + const Register x_xstart = zlen; // reuse register + + // First Loop. + // + // final static long LONG_MASK = 0xffffffffL; + // int xstart = xlen - 1; + // int ystart = ylen - 1; + // long carry = 0; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry; + // z[kdx] = (int)product; + // carry = product >>> 32; + // } + // z[xstart] = (int)carry; + // + + movw(idx, ylen); // idx = ylen; + movw(kdx, zlen); // kdx = xlen+ylen; + mov(carry, zr); // carry = 0; + + Label L_done; + + movw(xstart, xlen); + subsw(xstart, xstart, 1); + br(Assembler::MI, L_done); + + multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + + Label L_second_loop; + cbzw(kdx, L_second_loop); + + Label L_carry; + subw(kdx, kdx, 1); + cbzw(kdx, L_carry); + + strw(carry, Address(z, kdx, Address::uxtw(LogBytesPerInt))); + lsr(carry, carry, 32); + subw(kdx, kdx, 1); + + bind(L_carry); + strw(carry, Address(z, kdx, Address::uxtw(LogBytesPerInt))); + + // Second and third (nested) loops. + // + // for (int i = xstart-1; i >= 0; i--) { // Second loop + // carry = 0; + // for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop + // long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) + + // (z[k] & LONG_MASK) + carry; + // z[k] = (int)product; + // carry = product >>> 32; + // } + // z[i] = (int)carry; + // } + // + // i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = product_hi + + const Register jdx = tmp1; + + bind(L_second_loop); + mov(carry, zr); // carry = 0; + movw(jdx, ylen); // j = ystart+1 + + subsw(xstart, xstart, 1); // i = xstart-1; + br(Assembler::MI, L_done); + + str(z, Address(pre(sp, -4 * wordSize))); + + Label L_last_x; + lea(z, offsetted_address(z, xstart, Address::uxtw(LogBytesPerInt), 4, BytesPerInt)); // z = z + k - j + subsw(xstart, xstart, 1); // i = xstart-1; + br(Assembler::MI, L_last_x); + + lea(rscratch1, Address(x, xstart, Address::uxtw(LogBytesPerInt))); + ldr(product_hi, Address(rscratch1)); + ror(product_hi, product_hi, 32); // convert big-endian to little-endian + + Label L_third_loop_prologue; + bind(L_third_loop_prologue); + + str(ylen, Address(sp, wordSize)); + stp(x, xstart, Address(sp, 2 * wordSize)); + multiply_128_x_128_loop(y, z, carry, x, jdx, ylen, product, + tmp2, x_xstart, tmp3, tmp4, tmp6, product_hi); + ldp(z, ylen, Address(post(sp, 2 * wordSize))); + ldp(x, xlen, Address(post(sp, 2 * wordSize))); // copy old xstart -> xlen + + addw(tmp3, xlen, 1); + strw(carry, Address(z, tmp3, Address::uxtw(LogBytesPerInt))); + subsw(tmp3, tmp3, 1); + br(Assembler::MI, L_done); + + lsr(carry, carry, 32); + strw(carry, Address(z, tmp3, Address::uxtw(LogBytesPerInt))); + b(L_second_loop); + + // Next infrequent code is moved outside loops. + bind(L_last_x); + ldrw(product_hi, Address(x, 0)); + b(L_third_loop_prologue); + + bind(L_done); +} + +/** * Emits code to update CRC-32 with a byte value according to constants in table * * @param [in,out]crc Register containing the crc. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,9 +167,8 @@ // aliases defined in AARCH64 spec - template - inline void cmpw(Register Rd, T imm) { subsw(zr, Rd, imm); } + inline void cmpw(Register Rd, T imm) { subsw(zr, Rd, imm); } inline void cmp(Register Rd, unsigned imm) { subs(zr, Rd, imm); } inline void cmnw(Register Rd, unsigned imm) { addsw(zr, Rd, imm); } @@ -1121,9 +1120,34 @@ Register tmp1, Register tmp2, Register tmp3, Register tmp4, int int_cnt1, Register result); - +private: + void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2); + void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) { + add2_with_carry(dest_hi, dest_hi, dest_lo, src1, src2); + } + void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp7, Register product_hi); +public: + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, + Register zlen, Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, Register tmp7); // ISB may be needed because of a safepoint void maybe_isb() { isb(); } + +private: + // Return the effective address r + (r1 << ext) + offset. + // Uses rscratch2. + Address offsetted_address(Register r, Register r1, Address::extend ext, + int offset, int size); }; // Used by aarch64.ad to control code generation diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2356,8 +2356,45 @@ return start; } -#undef __ -#define __ masm-> + /** + * Arguments: + * + * Input: + * c_rarg0 - x address + * c_rarg1 - x length + * c_rarg2 - y address + * c_rarg3 - y lenth + * c_rarg4 - z address + * c_rarg5 - z length + */ + address generate_multiplyToLen() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + + address start = __ pc(); + const Register x = r0; + const Register xlen = r1; + const Register y = r2; + const Register ylen = r3; + const Register z = r4; + const Register zlen = r5; + + const Register tmp1 = r10; + const Register tmp2 = r11; + const Register tmp3 = r12; + const Register tmp4 = r13; + const Register tmp5 = r14; + const Register tmp6 = r15; + const Register tmp7 = r16; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception @@ -2375,6 +2412,9 @@ // otherwise assume that stack unwinding will be initiated, so // caller saved registers were assumed volatile in the compiler. +#undef __ +#define __ masm-> + address generate_throw_exception(const char* name, address runtime_entry, Register arg1 = noreg, @@ -2518,6 +2558,10 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } + #ifndef BUILTIN_SIM if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,6 +193,15 @@ } } + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); + } + + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + UseMultiplyToLenIntrinsic = true; + } + #ifdef COMPILER2 if (FLAG_IS_DEFAULT(OptoScheduling)) { OptoScheduling = true; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -466,7 +466,7 @@ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, entry_sp); + adaptername, mh_reg_name, p2i(mh), p2i(entry_sp)); if (Verbose) { tty->print_cr("Registers:"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,6 +172,12 @@ FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } + // This machine does not allow unaligned memory accesses + if (UseUnalignedAccesses) { + if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } } void VM_Version::print_features() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; -unsigned int VM_Version::_L2_cache_line_size = 0; +unsigned int VM_Version::_L2_data_cache_line_size = 0; void VM_Version::initialize() { _features = determine_features(); @@ -356,10 +356,17 @@ (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; + // This machine does not allow unaligned memory accesses + if (UseUnalignedAccesses) { + if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); - tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); + tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -96,8 +96,8 @@ static int _features; static const char* _features_str; - static unsigned int _L2_cache_line_size; - static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } + static unsigned int _L2_data_cache_line_size; + static unsigned int L2_data_cache_line_size() { return _L2_data_cache_line_size; } static void print_features(); static int determine_features(); @@ -171,7 +171,7 @@ static const char* cpu_features() { return _features_str; } // default prefetch block size on sparc - static intx prefetch_data_size() { return L2_cache_line_size(); } + static intx prefetch_data_size() { return L2_data_cache_line_size(); } // Prefetch static intx prefetch_copy_interval_in_bytes() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -3359,6 +3359,20 @@ // Integer vector arithmetic +void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { + assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); + int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38); + emit_int8(0x01); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { + assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); + int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38); + emit_int8(0x02); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::paddb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith(0xFC, dst, src, VEX_SIMD_66); @@ -3379,6 +3393,20 @@ emit_simd_arith(0xD4, dst, src, VEX_SIMD_66); } +void Assembler::phaddw(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse3(), "")); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38); + emit_int8(0x01); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::phaddd(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse3(), "")); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38); + emit_int8(0x02); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); emit_vex_arith(0xFC, dst, nds, src, VEX_SIMD_66, vector256); @@ -3804,6 +3832,17 @@ emit_int8(0x01); } +void Assembler::vextractf128h(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_avx(), ""); + bool vector256 = true; + int encode = vex_prefix_and_encode(src, xnoreg, dst, VEX_SIMD_66, vector256, VEX_OPCODE_0F_3A); + emit_int8(0x19); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - insert into lower 128 bits + // 0x01 - insert into upper 128 bits + emit_int8(0x01); +} + void Assembler::vextractf128h(Address dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1777,6 +1777,12 @@ void vxorpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256); void vxorps(XMMRegister dst, XMMRegister nds, Address src, bool vector256); + // Add horizontal packed integers + void vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256); + void vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256); + void phaddw(XMMRegister dst, XMMRegister src); + void phaddd(XMMRegister dst, XMMRegister src); + // Add packed integers void paddb(XMMRegister dst, XMMRegister src); void paddw(XMMRegister dst, XMMRegister src); @@ -1869,6 +1875,7 @@ // Copy low 128bit into high 128bit of YMM registers. void vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src); void vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src); + void vextractf128h(XMMRegister dst, XMMRegister src); // Load/store high 128bit of YMM registers which does not destroy other half. void vinsertf128h(XMMRegister dst, Address src); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp --- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,4 +58,9 @@ #endif #endif +#if defined(COMPILER2) && !defined(JAVASE_EMBEDDED) +// Include Restricted Transactional Memory lock eliding optimization +#define INCLUDE_RTM_OPT 1 +#endif + #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/rtmLocking.cpp --- a/hotspot/src/cpu/x86/vm/rtmLocking.cpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/task.hpp" -#include "runtime/rtmLocking.hpp" - -// One-shot PeriodicTask subclass for enabling RTM locking -uintx RTMLockingCounters::_calculation_flag = 0; - -class RTMLockingCalculationTask : public PeriodicTask { - public: - RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } - - virtual void task() { - RTMLockingCounters::_calculation_flag = 1; - // Reclaim our storage and disenroll ourself - delete this; - } -}; - -void RTMLockingCounters::init() { - if (UseRTMLocking && RTMLockingCalculationDelay > 0) { - RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); - task->enroll(); - } else { - _calculation_flag = 1; - } -} - -//------------------------------print_on------------------------------- -void RTMLockingCounters::print_on(outputStream* st) { - tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); - tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); - for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { - tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); - } -} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -969,6 +969,11 @@ (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); + } + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("Logical CPUs per core: %u", diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/x86.ad --- a/hotspot/src/cpu/x86/vm/x86.ad Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/x86.ad Fri Apr 17 14:37:20 2015 -0700 @@ -490,7 +490,7 @@ class NativeJump; class CallStubImpl { - + //-------------------------------------------------------------- //---< Used for optimization in Compile::shorten_branches >--- //-------------------------------------------------------------- @@ -500,9 +500,9 @@ static uint size_call_trampoline() { return 0; // no call trampolines on this platform } - + // number of relocations needed by a call trampoline stub - static uint reloc_call_trampoline() { + static uint reloc_call_trampoline() { return 0; // no call trampolines on this platform } }; @@ -623,6 +623,22 @@ if ((UseSSE < 4) && (UseAVX < 1)) // only with SSE4_1 or AVX return false; break; + case Op_AddReductionVL: + if (UseAVX < 3) // only EVEX : vector connectivity becomes an issue here + return false; + case Op_AddReductionVI: + if (UseSSE < 3) // requires at least SSE3 + return false; + case Op_MulReductionVI: + if (UseSSE < 4) // requires at least SSE4 + return false; + case Op_AddReductionVF: + case Op_AddReductionVD: + case Op_MulReductionVF: + case Op_MulReductionVD: + if (UseSSE < 1) // requires at least SSE + return false; + break; case Op_CompareAndSwapL: #ifdef _LP64 case Op_CompareAndSwapP: @@ -2532,6 +2548,574 @@ ins_pipe( fpu_reg_reg ); %} +// ====================REDUCTION ARITHMETIC======================================= + +instruct rsadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 2 && UseAVX == 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "movdqu $tmp2,$src2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "movd $tmp,$src1\n\t" + "paddd $tmp,$tmp2\n\t" + "movd $dst,$tmp\t! add reduction2I" %} + ins_encode %{ + __ movdqu($tmp2$$XMMRegister, $src2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ paddd($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($dst$$Register, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction2I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 2 && UseAVX == 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "movdqu $tmp2,$src2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "movd $tmp,$src1\n\t" + "paddd $tmp,$tmp2\n\t" + "movd $dst,$tmp\t! add reduction4I" %} + ins_encode %{ + __ movdqu($tmp2$$XMMRegister, $src2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ paddd($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($dst$$Register, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "vphaddd $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction4I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, false); + __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd8I_reduction_reg(rRegI dst, rRegI src1, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "vphaddd $tmp,$tmp,$tmp2\n\t" + "vextractf128 $tmp2,$tmp\n\t" + "vpaddd $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction8I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, true); + __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, true); + __ vextractf128h($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vpaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "addss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "addss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction2F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction2F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "addss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "addss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x02\n\t" + "addss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x03\n\t" + "addss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction4F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction4F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct radd8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vaddss $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x03\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction8F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP dst); + format %{ "movdqu $tmp,$src1\n\t" + "addsd $tmp,$src2\n\t" + "pshufd $dst,$src2,0xE\n\t" + "addsd $dst,$tmp\t! add reduction2D" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addsd($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ addsd($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vaddsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vaddsd $dst,$tmp2,$tmp\t! add reduction2D" %} + ins_encode %{ + __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vaddsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vaddsd $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vaddsd $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0xE\n\t" + "vaddsd $dst,$tmp2,$tmp\t! add reduction4D" %} + ins_encode %{ + __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 3 && UseAVX == 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0x1\n\t" + "pmulld $tmp2,$src2\n\t" + "movd $tmp,$src1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! mul reduction2I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ pmulld($tmp2$$XMMRegister, $src2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0x1\n\t" + "vpmulld $tmp,$src2,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction2I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $src2$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 3 && UseAVX == 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0xE\n\t" + "pmulld $tmp2,$src2\n\t" + "pshufd $tmp,$tmp2,0x1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $tmp,$src1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! mul reduction4I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0xE); + __ pmulld($tmp2$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x1); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0xE\n\t" + "vpmulld $tmp,$src2,$tmp2\n\t" + "pshufd $tmp2,$tmp,0x1\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction4I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vpmulld($tmp$$XMMRegister, $src2$$XMMRegister, $tmp2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul8I_reduction_reg(rRegI dst, rRegI src1, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vextractf128 $tmp,$src2\n\t" + "vpmulld $tmp,$tmp,$src2\n\t" + "pshufd $tmp2,$tmp,0xE\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "pshufd $tmp2,$tmp,0x1\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction8I" %} + ins_encode %{ + __ vextractf128h($tmp$$XMMRegister, $src2$$XMMRegister); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $src2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0xE); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "mulss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "mulss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction2F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$tmp2,$tmp\t! add reduction2F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "mulss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "mulss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x02\n\t" + "mulss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x03\n\t" + "mulss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction4F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $dst,$tmp2,$tmp\t! add reduction4F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vmulss $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x03\n\t" + "vmulss $dst,$tmp2,$tmp\t! mul reduction8F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP dst); + format %{ "movdqu $tmp,$src1\n\t" + "mulsd $tmp,$src2\n\t" + "pshufd $dst,$src2,0xE\n\t" + "mulsd $dst,$tmp\t! add reduction2D" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulsd($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ mulsd($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vmulsd $dst,$tmp2,$tmp\t! mul reduction2D" %} + ins_encode %{ + __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vmulsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vmulsd $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vmulsd $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0xE\n\t" + "vmulsd $dst,$tmp2,$tmp\t! mul reduction4D" %} + ins_encode %{ + __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + // ====================VECTOR ARITHMETIC======================================= // --------------------------------- ADD -------------------------------------- diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Fri Apr 17 14:37:20 2015 -0700 @@ -3604,6 +3604,23 @@ %} %} +// Indirect Memory Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffset(any_RegP reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP reg (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -3755,6 +3772,23 @@ %} %} +// Indirect Memory Times Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffsetNarrow(rRegN reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -3946,11 +3980,11 @@ // case of this is memory operands. opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, - indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset, + indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, - indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); + indIndexScaleOffsetNarrow, indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -4984,6 +5018,17 @@ ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxOff(rRegP dst, indPosIndexOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoff" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) %{ match(Set dst mem); @@ -5068,6 +5113,18 @@ ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxOffNarrow(rRegP dst, indPosIndexOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) %{ predicate(Universe::narrow_oop_shift() == 0); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/cpu/zero/vm/vm_version_zero.cpp --- a/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,4 +30,11 @@ #include "runtime/stubCodeGenerator.hpp" #include "vm_version_zero.hpp" -// This file is intentionally empty + +void VM_Version::initialize() { + // This machine does not allow unaligned memory accesses + if (! FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/attachListener_aix.cpp --- a/hotspot/src/os/aix/vm/attachListener_aix.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/attachListener_aix.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,6 +144,10 @@ } char* next() { if (*_pos == '\0') { + if (_pos < _end) { + _pos += 1; + } + return NULL; } char* res = _pos; @@ -214,6 +218,7 @@ // bind socket struct sockaddr_un addr; + memset((void *)&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, initial_path); ::unlink(initial_path); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/globals_aix.hpp --- a/hotspot/src/os/aix/vm/globals_aix.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/globals_aix.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,10 @@ // #define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ \ + /* Use 64K pages for virtual memory (shmat). */ \ + product(bool, Use64KPages, true, \ + "Use 64K pages if available.") \ + \ /* If UseLargePages == true allow or deny usage of 16M pages. 16M pages are */ \ /* a scarce resource and there may be situations where we do not want the VM */ \ /* to run with 16M pages. (Will fall back to 64K pages). */ \ @@ -55,7 +59,7 @@ // Defines Aix-specific default values. The flags are available on all // platforms, but they may have different default values on other platforms. // -define_pd_global(bool, UseLargePages, true); +define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/interfaceSupport_aix.hpp --- a/hotspot/src/os/aix/vm/interfaceSupport_aix.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/interfaceSupport_aix.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ * */ -#ifndef OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP -#define OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP +#ifndef OS_AIX_VM_INTERFACESUPPORT_AIX_HPP +#define OS_AIX_VM_INTERFACESUPPORT_AIX_HPP // Contains inlined functions for class InterfaceSupport @@ -32,4 +32,4 @@ os::write_memory_serialize_page(thread); } -#endif // OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP +#endif // OS_AIX_VM_INTERFACESUPPORT_AIX_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/osThread_aix.cpp --- a/hotspot/src/os/aix/vm/osThread_aix.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/osThread_aix.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true, Monitor::_safepoint_check_never); - assert(_startThread_lock !=NULL, "check"); + assert(_startThread_lock != NULL, "check"); } void OSThread::pd_destroy() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,6 +113,10 @@ #define RUSAGE_THREAD (1) /* only the calling thread */ #endif +// PPC port +static const uintx Use64KPagesThreshold = 1*M; +static const uintx MaxExpectedDataSegmentSize = SIZE_4G*2; + // Add missing declarations (should be in procinfo.h but isn't until AIX 6.1). #if !defined(_AIXVERSION_610) extern "C" { @@ -168,8 +172,8 @@ return -1; \ } -// query dimensions of the stack of the calling thread -static void query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); +// Query dimensions of the stack of the calling thread. +static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); // function to check a given stack pointer against given stack limits inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) { @@ -220,9 +224,6 @@ int os::Aix::_on_pase = -1; int os::Aix::_os_version = -1; int os::Aix::_stack_page_size = -1; -size_t os::Aix::_shm_default_page_size = -1; -int os::Aix::_can_use_64K_pages = -1; -int os::Aix::_can_use_16M_pages = -1; int os::Aix::_xpg_sus_mode = -1; int os::Aix::_extshm = -1; int os::Aix::_logical_cpus = -1; @@ -239,6 +240,63 @@ static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769) static sigset_t SR_sigset; +// This describes the state of multipage support of the underlying +// OS. Note that this is of no interest to the outsize world and +// therefore should not be defined in AIX class. +// +// AIX supports four different page sizes - 4K, 64K, 16MB, 16GB. The +// latter two (16M "large" resp. 16G "huge" pages) require special +// setup and are normally not available. +// +// AIX supports multiple page sizes per process, for: +// - Stack (of the primordial thread, so not relevant for us) +// - Data - data, bss, heap, for us also pthread stacks +// - Text - text code +// - shared memory +// +// Default page sizes can be set via linker options (-bdatapsize, -bstacksize, ...) +// and via environment variable LDR_CNTRL (DATAPSIZE, STACKPSIZE, ...). +// +// For shared memory, page size can be set dynamically via +// shmctl(). Different shared memory regions can have different page +// sizes. +// +// More information can be found at AIBM info center: +// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm +// +static struct { + size_t pagesize; // sysconf _SC_PAGESIZE (4K) + size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) + size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) + size_t pthr_stack_pagesize; // stack page size of pthread threads + size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) + bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. + bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. + int error; // Error describing if something went wrong at multipage init. +} g_multipage_support = { + (size_t) -1, + (size_t) -1, + (size_t) -1, + (size_t) -1, + (size_t) -1, + false, false, + 0 +}; + +// We must not accidentally allocate memory close to the BRK - even if +// that would work - because then we prevent the BRK segment from +// growing which may result in a malloc OOM even though there is +// enough memory. The problem only arises if we shmat() or mmap() at +// a specific wish address, e.g. to place the heap in a +// compressed-oops-friendly way. +static bool is_close_to_brk(address a) { + address a1 = (address) sbrk(0); + if (a >= a1 && a < (a1 + MaxExpectedDataSegmentSize)) { + return true; + } + return false; +} + julong os::available_memory() { return Aix::available_memory(); } @@ -277,7 +335,7 @@ } // Maximum size 32bit disclaim() accepts. (Theoretically 4GB, but I just do not trust that.) - const unsigned int maxDisclaimSize = 0x80000000; + const unsigned int maxDisclaimSize = 0x40000000; const unsigned int numFullDisclaimsNeeded = (size / maxDisclaimSize); const unsigned int lastDisclaimSize = (size % maxDisclaimSize); @@ -354,138 +412,131 @@ case SIZE_64K: return "64K"; case SIZE_16M: return "16M"; case SIZE_16G: return "16G"; + case -1: return "not set"; default: assert(false, "surprise"); return "??"; } } -// Retrieve information about multipage size support. Will initialize -// Aix::_page_size, Aix::_stack_page_size, Aix::_can_use_64K_pages, -// Aix::_can_use_16M_pages. +// Probe OS for multipage support. +// Will fill the global g_multipage_support structure. // Must be called before calling os::large_page_init(). -void os::Aix::query_multipage_support() { - - guarantee(_page_size == -1 && - _stack_page_size == -1 && - _can_use_64K_pages == -1 && - _can_use_16M_pages == -1 && - g_multipage_error == -1, +static void query_multipage_support() { + + guarantee(g_multipage_support.pagesize == -1, "do not call twice"); - _page_size = ::sysconf(_SC_PAGESIZE); + g_multipage_support.pagesize = ::sysconf(_SC_PAGESIZE); // This really would surprise me. - assert(_page_size == SIZE_4K, "surprise!"); - + assert(g_multipage_support.pagesize == SIZE_4K, "surprise!"); // Query default data page size (default page size for C-Heap, pthread stacks and .bss). - // Default data page size is influenced either by linker options (-bdatapsize) + // Default data page size is defined either by linker options (-bdatapsize) // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. - size_t data_page_size = SIZE_4K; { - void* p = os::malloc(SIZE_16M, mtInternal); - guarantee(p != NULL, "malloc failed"); - data_page_size = os::Aix::query_pagesize(p); - os::free(p); - } - - // query default shm page size (LDR_CNTRL SHMPSIZE) + void* p = ::malloc(SIZE_16M); + g_multipage_support.datapsize = os::Aix::query_pagesize(p); + ::free(p); + } + + // Query default shm page size (LDR_CNTRL SHMPSIZE). { const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); guarantee(shmid != -1, "shmget failed"); void* p = ::shmat(shmid, NULL, 0); ::shmctl(shmid, IPC_RMID, NULL); guarantee(p != (void*) -1, "shmat failed"); - _shm_default_page_size = os::Aix::query_pagesize(p); + g_multipage_support.shmpsize = os::Aix::query_pagesize(p); ::shmdt(p); } - // before querying the stack page size, make sure we are not running as primordial + // Before querying the stack page size, make sure we are not running as primordial // thread (because primordial thread's stack may have different page size than // pthread thread stacks). Running a VM on the primordial thread won't work for a - // number of reasons so we may just as well guarantee it here - guarantee(!os::Aix::is_primordial_thread(), "Must not be called for primordial thread"); - - // query stack page size + // number of reasons so we may just as well guarantee it here. + guarantee0(!os::Aix::is_primordial_thread()); + + // Query pthread stack page size. { int dummy = 0; - _stack_page_size = os::Aix::query_pagesize(&dummy); - // everything else would surprise me and should be looked into - guarantee(_stack_page_size == SIZE_4K || _stack_page_size == SIZE_64K, "Wrong page size"); - // also, just for completeness: pthread stacks are allocated from C heap, so - // stack page size should be the same as data page size - guarantee(_stack_page_size == data_page_size, "stack page size should be the same as data page size"); - } - - // EXTSHM is bad: among other things, it prevents setting pagesize dynamically - // for system V shm. - if (Aix::extshm()) { - if (Verbose) { - fprintf(stderr, "EXTSHM is active - will disable large page support.\n" - "Please make sure EXTSHM is OFF for large page support.\n"); - } - g_multipage_error = ERROR_MP_EXTSHM_ACTIVE; - _can_use_64K_pages = _can_use_16M_pages = 0; + g_multipage_support.pthr_stack_pagesize = os::Aix::query_pagesize(&dummy); + } + + // Query default text page size (LDR_CNTRL TEXTPSIZE). + /* PPC port: so far unused. + { + address any_function = + (address) resolve_function_descriptor_to_code_pointer((address)describe_pagesize); + g_multipage_support.textpsize = os::Aix::query_pagesize(any_function); + } + */ + + // Now probe for support of 64K pages and 16M pages. + + // Before OS/400 V6R1, there is no support for pages other than 4K. + if (os::Aix::on_pase_V5R4_or_older()) { + Unimplemented(); goto query_multipage_support_end; } - // now check which page sizes the OS claims it supports, and of those, which actually can be used. + // Now check which page sizes the OS claims it supports, and of those, which actually can be used. { const int MAX_PAGE_SIZES = 4; psize_t sizes[MAX_PAGE_SIZES]; const int num_psizes = ::vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES); if (num_psizes == -1) { - if (Verbose) { - fprintf(stderr, "vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno); - fprintf(stderr, "disabling multipage support.\n"); - } - g_multipage_error = ERROR_MP_VMGETINFO_FAILED; - _can_use_64K_pages = _can_use_16M_pages = 0; + trc("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno); + trc("disabling multipage support.\n"); + g_multipage_support.error = ERROR_MP_VMGETINFO_FAILED; goto query_multipage_support_end; } guarantee(num_psizes > 0, "vmgetinfo(.., VMINFO_GETPSIZES, ...) failed."); assert(num_psizes <= MAX_PAGE_SIZES, "Surprise! more than 4 page sizes?"); - if (Verbose) { - fprintf(stderr, "vmgetinfo(.., VMINFO_GETPSIZES, ...) returns %d supported page sizes: ", num_psizes); - for (int i = 0; i < num_psizes; i ++) { - fprintf(stderr, " %s ", describe_pagesize(sizes[i])); - } - fprintf(stderr, " .\n"); + trcVerbose("vmgetinfo(.., VMINFO_GETPSIZES, ...) returns %d supported page sizes: ", num_psizes); + for (int i = 0; i < num_psizes; i ++) { + trcVerbose(" %s ", describe_pagesize(sizes[i])); } // Can we use 64K, 16M pages? - _can_use_64K_pages = 0; - _can_use_16M_pages = 0; for (int i = 0; i < num_psizes; i ++) { - if (sizes[i] == SIZE_64K) { - _can_use_64K_pages = 1; - } else if (sizes[i] == SIZE_16M) { - _can_use_16M_pages = 1; + const size_t pagesize = sizes[i]; + if (pagesize != SIZE_64K && pagesize != SIZE_16M) { + continue; } - } - - if (!_can_use_64K_pages) { - g_multipage_error = ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K; - } - - // Double-check for 16M pages: Even if AIX claims to be able to use 16M pages, - // there must be an actual 16M page pool, and we must run with enough rights. - if (_can_use_16M_pages) { - const int shmid = ::shmget(IPC_PRIVATE, SIZE_16M, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee(shmid != -1, "shmget failed"); + bool can_use = false; + trcVerbose("Probing support for %s pages...", describe_pagesize(pagesize)); + const int shmid = ::shmget(IPC_PRIVATE, pagesize, + IPC_CREAT | S_IRUSR | S_IWUSR); + guarantee0(shmid != -1); // Should always work. + // Try to set pagesize. struct shmid_ds shm_buf = { 0 }; - shm_buf.shm_pagesize = SIZE_16M; - const bool can_set_pagesize = ::shmctl(shmid, SHM_PAGESIZE, &shm_buf) == 0 ? true : false; - const int en = errno; - ::shmctl(shmid, IPC_RMID, NULL); - if (!can_set_pagesize) { - if (Verbose) { - fprintf(stderr, "Failed to allocate even one misely 16M page. shmctl failed with %d (%s).\n" - "Will deactivate 16M support.\n", en, strerror(en)); + shm_buf.shm_pagesize = pagesize; + if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { + const int en = errno; + ::shmctl(shmid, IPC_RMID, NULL); // As early as possible! + // PPC port trcVerbose("shmctl(SHM_PAGESIZE) failed with %s", + // PPC port MiscUtils::describe_errno(en)); + } else { + // Attach and double check pageisze. + void* p = ::shmat(shmid, NULL, 0); + ::shmctl(shmid, IPC_RMID, NULL); // As early as possible! + guarantee0(p != (void*) -1); // Should always work. + const size_t real_pagesize = os::Aix::query_pagesize(p); + if (real_pagesize != pagesize) { + trcVerbose("real page size (0x%llX) differs.", real_pagesize); + } else { + can_use = true; } - _can_use_16M_pages = 0; + ::shmdt(p); + } + trcVerbose("Can use: %s", (can_use ? "yes" : "no")); + if (pagesize == SIZE_64K) { + g_multipage_support.can_use_64K_pages = can_use; + } else if (pagesize == SIZE_16M) { + g_multipage_support.can_use_16M_pages = can_use; } } @@ -493,23 +544,29 @@ query_multipage_support_end: - guarantee(_page_size != -1 && - _stack_page_size != -1 && - _can_use_64K_pages != -1 && - _can_use_16M_pages != -1, "Page sizes not properly initialized"); - - if (_can_use_64K_pages) { - g_multipage_error = 0; - } - - if (Verbose) { - fprintf(stderr, "Data page size (C-Heap, bss, etc): %s\n", describe_pagesize(data_page_size)); - fprintf(stderr, "Thread stack page size (pthread): %s\n", describe_pagesize(_stack_page_size)); - fprintf(stderr, "Default shared memory page size: %s\n", describe_pagesize(_shm_default_page_size)); - fprintf(stderr, "Can use 64K pages dynamically with shared meory: %s\n", (_can_use_64K_pages ? "yes" :"no")); - fprintf(stderr, "Can use 16M pages dynamically with shared memory: %s\n", (_can_use_16M_pages ? "yes" :"no")); - fprintf(stderr, "Multipage error details: %d\n", g_multipage_error); - } + trcVerbose("base page size (sysconf _SC_PAGESIZE): %s\n", + describe_pagesize(g_multipage_support.pagesize)); + trcVerbose("Data page size (C-Heap, bss, etc): %s\n", + describe_pagesize(g_multipage_support.datapsize)); + trcVerbose("Text page size: %s\n", + describe_pagesize(g_multipage_support.textpsize)); + trcVerbose("Thread stack page size (pthread): %s\n", + describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + trcVerbose("Default shared memory page size: %s\n", + describe_pagesize(g_multipage_support.shmpsize)); + trcVerbose("Can use 64K pages dynamically with shared meory: %s\n", + (g_multipage_support.can_use_64K_pages ? "yes" :"no")); + trcVerbose("Can use 16M pages dynamically with shared memory: %s\n", + (g_multipage_support.can_use_16M_pages ? "yes" :"no")); + trcVerbose("Multipage error details: %d\n", + g_multipage_support.error); + + // sanity checks + assert0(g_multipage_support.pagesize == SIZE_4K); + assert0(g_multipage_support.datapsize == SIZE_4K || g_multipage_support.datapsize == SIZE_64K); + // PPC port: so far unused.assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K); + assert0(g_multipage_support.pthr_stack_pagesize == g_multipage_support.datapsize); + assert0(g_multipage_support.shmpsize == SIZE_4K || g_multipage_support.shmpsize == SIZE_64K); } // end os::Aix::query_multipage_support() @@ -1557,9 +1614,12 @@ st->print_cr(" default page size: %s", describe_pagesize(os::vm_page_size())); st->print_cr(" default stack page size: %s", describe_pagesize(os::vm_page_size())); - st->print_cr(" default shm page size: %s", describe_pagesize(os::Aix::shm_default_page_size())); - st->print_cr(" can use 64K pages dynamically: %s", (os::Aix::can_use_64K_pages() ? "yes" :"no")); - st->print_cr(" can use 16M pages dynamically: %s", (os::Aix::can_use_16M_pages() ? "yes" :"no")); + st->print_cr(" Default shared memory page size: %s", + describe_pagesize(g_multipage_support.shmpsize)); + st->print_cr(" Can use 64K pages dynamically with shared meory: %s", + (g_multipage_support.can_use_64K_pages ? "yes" :"no")); + st->print_cr(" Can use 16M pages dynamically with shared memory: %s", + (g_multipage_support.can_use_16M_pages ? "yes" :"no")); if (g_multipage_error != 0) { st->print_cr(" multipage error: %d", g_multipage_error); } @@ -1570,6 +1630,9 @@ const char* const extshm = ::getenv("EXTSHM"); st->print_cr(" EXTSHM=%s.", extshm ? extshm : ""); + if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) { + st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***"); + } // Call os::Aix::get_meminfo() to retrieve memory statistics. os::Aix::meminfo_t mi; @@ -1812,315 +1875,386 @@ //////////////////////////////////////////////////////////////////////////////// // Virtual Memory -// AddrRange describes an immutable address range -// -// This is a helper class for the 'shared memory bookkeeping' below. -class AddrRange { - friend class ShmBkBlock; - - char* _start; - size_t _size; - -public: - - AddrRange(char* start, size_t size) - : _start(start), _size(size) - {} - - AddrRange(const AddrRange& r) - : _start(r.start()), _size(r.size()) - {} - - char* start() const { return _start; } - size_t size() const { return _size; } - char* end() const { return _start + _size; } - bool is_empty() const { return _size == 0 ? true : false; } - - static AddrRange empty_range() { return AddrRange(NULL, 0); } - - bool contains(const char* p) const { - return start() <= p && end() > p; - } - - bool contains(const AddrRange& range) const { - return start() <= range.start() && end() >= range.end(); - } - - bool intersects(const AddrRange& range) const { - return (range.start() <= start() && range.end() > start()) || - (range.start() < end() && range.end() >= end()) || - contains(range); - } - - bool is_same_range(const AddrRange& range) const { - return start() == range.start() && size() == range.size(); - } - - // return the closest inside range consisting of whole pages - AddrRange find_closest_aligned_range(size_t pagesize) const { - if (pagesize == 0 || is_empty()) { - return empty_range(); +// We need to keep small simple bookkeeping for os::reserve_memory and friends. + +#define VMEM_MAPPED 1 +#define VMEM_SHMATED 2 + +struct vmembk_t { + int type; // 1 - mmap, 2 - shmat + char* addr; + size_t size; // Real size, may be larger than usersize. + size_t pagesize; // page size of area + vmembk_t* next; + + bool contains_addr(char* p) const { + return p >= addr && p < (addr + size); + } + + bool contains_range(char* p, size_t s) const { + return contains_addr(p) && contains_addr(p + s - 1); + } + + void print_on(outputStream* os) const { + os->print("[" PTR_FORMAT " - " PTR_FORMAT "] (" UINTX_FORMAT + " bytes, %d %s pages), %s", + addr, addr + size - 1, size, size / pagesize, describe_pagesize(pagesize), + (type == VMEM_SHMATED ? "shmat" : "mmap") + ); + } + + // Check that range is a sub range of memory block (or equal to memory block); + // also check that range is fully page aligned to the page size if the block. + void assert_is_valid_subrange(char* p, size_t s) const { + if (!contains_range(p, s)) { + fprintf(stderr, "[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub " + "range of [" PTR_FORMAT " - " PTR_FORMAT "].\n", + p, p + s - 1, addr, addr + size - 1); + guarantee0(false); } - char* const from = (char*)align_size_up((intptr_t)_start, pagesize); - char* const to = (char*)align_size_down((intptr_t)end(), pagesize); - if (from > to) { - return empty_range(); + if (!is_aligned_to(p, pagesize) || !is_aligned_to(p + s, pagesize)) { + fprintf(stderr, "range [" PTR_FORMAT " - " PTR_FORMAT "] is not" + " aligned to pagesize (%s)\n", p, p + s); + guarantee0(false); } - return AddrRange(from, to - from); } }; -//////////////////////////////////////////////////////////////////////////// -// shared memory bookkeeping -// -// the os::reserve_memory() API and friends hand out different kind of memory, depending -// on need and circumstances. Memory may be allocated with mmap() or with shmget/shmat. -// -// But these memory types have to be treated differently. For example, to uncommit -// mmap-based memory, msync(MS_INVALIDATE) is needed, to uncommit shmat-based memory, -// disclaim64() is needed. -// -// Therefore we need to keep track of the allocated memory segments and their -// properties. - -// ShmBkBlock: base class for all blocks in the shared memory bookkeeping -class ShmBkBlock : public CHeapObj { - - ShmBkBlock* _next; - -protected: - - AddrRange _range; - const size_t _pagesize; - const bool _pinned; - -public: - - ShmBkBlock(AddrRange range, size_t pagesize, bool pinned) - : _range(range), _pagesize(pagesize), _pinned(pinned) , _next(NULL) { - - assert(_pagesize == SIZE_4K || _pagesize == SIZE_64K || _pagesize == SIZE_16M, "invalid page size"); - assert(!_range.is_empty(), "invalid range"); - } - - virtual void print(outputStream* st) const { - st->print("0x%p ... 0x%p (%llu) - %d %s pages - %s", - _range.start(), _range.end(), _range.size(), - _range.size() / _pagesize, describe_pagesize(_pagesize), - _pinned ? "pinned" : ""); - } - - enum Type { MMAP, SHMAT }; - virtual Type getType() = 0; - - char* base() const { return _range.start(); } - size_t size() const { return _range.size(); } - - void setAddrRange(AddrRange range) { - _range = range; - } - - bool containsAddress(const char* p) const { - return _range.contains(p); - } - - bool containsRange(const char* p, size_t size) const { - return _range.contains(AddrRange((char*)p, size)); - } - - bool isSameRange(const char* p, size_t size) const { - return _range.is_same_range(AddrRange((char*)p, size)); - } - - virtual bool disclaim(char* p, size_t size) = 0; - virtual bool release() = 0; - - // blocks live in a list. - ShmBkBlock* next() const { return _next; } - void set_next(ShmBkBlock* blk) { _next = blk; } - -}; // end: ShmBkBlock - - -// ShmBkMappedBlock: describes an block allocated with mmap() -class ShmBkMappedBlock : public ShmBkBlock { -public: - - ShmBkMappedBlock(AddrRange range) - : ShmBkBlock(range, SIZE_4K, false) {} // mmap: always 4K, never pinned - - void print(outputStream* st) const { - ShmBkBlock::print(st); - st->print_cr(" - mmap'ed"); - } - - Type getType() { - return MMAP; - } - - bool disclaim(char* p, size_t size) { - - AddrRange r(p, size); - - guarantee(_range.contains(r), "invalid disclaim"); - - // only disclaim whole ranges. - const AddrRange r2 = r.find_closest_aligned_range(_pagesize); - if (r2.is_empty()) { - return true; +static struct { + vmembk_t* first; + MiscUtils::CritSect cs; +} vmem; + +static void vmembk_add(char* addr, size_t size, size_t pagesize, int type) { + vmembk_t* p = (vmembk_t*) ::malloc(sizeof(vmembk_t)); + assert0(p); + if (p) { + MiscUtils::AutoCritSect lck(&vmem.cs); + p->addr = addr; p->size = size; + p->pagesize = pagesize; + p->type = type; + p->next = vmem.first; + vmem.first = p; + } +} + +static vmembk_t* vmembk_find(char* addr) { + MiscUtils::AutoCritSect lck(&vmem.cs); + for (vmembk_t* p = vmem.first; p; p = p->next) { + if (p->addr <= addr && (p->addr + p->size) > addr) { + return p; } - - const int rc = ::msync(r2.start(), r2.size(), MS_INVALIDATE); - - if (rc != 0) { - warning("msync(0x%p, %llu, MS_INVALIDATE) failed (%d)\n", r2.start(), r2.size(), errno); - } - - return rc == 0 ? true : false; - } - - bool release() { - // mmap'ed blocks are released using munmap - if (::munmap(_range.start(), _range.size()) != 0) { - warning("munmap(0x%p, %llu) failed (%d)\n", _range.start(), _range.size(), errno); - return false; - } - return true; - } -}; // end: ShmBkMappedBlock - -// ShmBkShmatedBlock: describes an block allocated with shmget/shmat() -class ShmBkShmatedBlock : public ShmBkBlock { -public: - - ShmBkShmatedBlock(AddrRange range, size_t pagesize, bool pinned) - : ShmBkBlock(range, pagesize, pinned) {} - - void print(outputStream* st) const { - ShmBkBlock::print(st); - st->print_cr(" - shmat'ed"); - } - - Type getType() { - return SHMAT; - } - - bool disclaim(char* p, size_t size) { - - AddrRange r(p, size); - - if (_pinned) { - return true; - } - - // shmat'ed blocks are disclaimed using disclaim64 - guarantee(_range.contains(r), "invalid disclaim"); - - // only disclaim whole ranges. - const AddrRange r2 = r.find_closest_aligned_range(_pagesize); - if (r2.is_empty()) { - return true; - } - - const bool rc = my_disclaim64(r2.start(), r2.size()); - - if (Verbose && !rc) { - warning("failed to disclaim shm %p-%p\n", r2.start(), r2.end()); - } - - return rc; - } - - bool release() { - bool rc = false; - if (::shmdt(_range.start()) != 0) { - warning("shmdt(0x%p) failed (%d)\n", _range.start(), errno); - } else { - rc = true; - } - return rc; - } - -}; // end: ShmBkShmatedBlock - -static ShmBkBlock* g_shmbk_list = NULL; -static volatile jint g_shmbk_table_lock = 0; - -// keep some usage statistics -static struct { - int nodes; // number of nodes in list - size_t bytes; // reserved - not committed - bytes. - int reserves; // how often reserve was called - int lookups; // how often a lookup was made -} g_shmbk_stats = { 0, 0, 0, 0 }; - -// add information about a shared memory segment to the bookkeeping -static void shmbk_register(ShmBkBlock* p_block) { - guarantee(p_block, "logic error"); - p_block->set_next(g_shmbk_list); - g_shmbk_list = p_block; - g_shmbk_stats.reserves ++; - g_shmbk_stats.bytes += p_block->size(); - g_shmbk_stats.nodes ++; -} - -// remove information about a shared memory segment by its starting address -static void shmbk_unregister(ShmBkBlock* p_block) { - ShmBkBlock* p = g_shmbk_list; - ShmBkBlock* prev = NULL; - while (p) { - if (p == p_block) { - if (prev) { - prev->set_next(p->next()); - } else { - g_shmbk_list = p->next(); - } - g_shmbk_stats.nodes --; - g_shmbk_stats.bytes -= p->size(); + } + return NULL; +} + +static void vmembk_remove(vmembk_t* p0) { + MiscUtils::AutoCritSect lck(&vmem.cs); + assert0(p0); + assert0(vmem.first); // List should not be empty. + for (vmembk_t** pp = &(vmem.first); *pp; pp = &((*pp)->next)) { + if (*pp == p0) { + *pp = p0->next; + ::free(p0); return; } - prev = p; - p = p->next(); - } - assert(false, "should not happen"); -} - -// given a pointer, return shared memory bookkeeping record for the segment it points into -// using the returned block info must happen under lock protection -static ShmBkBlock* shmbk_find_by_containing_address(const char* addr) { - g_shmbk_stats.lookups ++; - ShmBkBlock* p = g_shmbk_list; - while (p) { - if (p->containsAddress(addr)) { - return p; + } + assert0(false); // Not found? +} + +static void vmembk_print_on(outputStream* os) { + MiscUtils::AutoCritSect lck(&vmem.cs); + for (vmembk_t* vmi = vmem.first; vmi; vmi = vmi->next) { + vmi->print_on(os); + os->cr(); + } +} + +// Reserve and attach a section of System V memory. +// If is not NULL, function will attempt to attach the memory at the given +// address. Failing that, it will attach the memory anywhere. +// If is NULL, function will attach the memory anywhere. +// +// is being ignored by this function. It is very probable however that the +// alignment requirements are met anyway, because shmat() attaches at 256M boundaries. +// Should this be not enogh, we can put more work into it. +static char* reserve_shmated_memory ( + size_t bytes, + char* requested_addr, + size_t alignment_hint) { + + trcVerbose("reserve_shmated_memory " UINTX_FORMAT " bytes, wishaddress " + PTR_FORMAT ", alignment_hint " UINTX_FORMAT "...", + bytes, requested_addr, alignment_hint); + + // Either give me wish address or wish alignment but not both. + assert0(!(requested_addr != NULL && alignment_hint != 0)); + + // We must prevent anyone from attaching too close to the + // BRK because that may cause malloc OOM. + if (requested_addr != NULL && is_close_to_brk((address)requested_addr)) { + trcVerbose("Wish address " PTR_FORMAT " is too close to the BRK segment. " + "Will attach anywhere.", requested_addr); + // Act like the OS refused to attach there. + requested_addr = NULL; + } + + // For old AS/400's (V5R4 and older) we should not even be here - System V shared memory is not + // really supported (max size 4GB), so reserve_mmapped_memory should have been used instead. + if (os::Aix::on_pase_V5R4_or_older()) { + ShouldNotReachHere(); + } + + // Align size of shm up to 64K to avoid errors if we later try to change the page size. + const size_t size = align_size_up(bytes, SIZE_64K); + + // Reserve the shared segment. + int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR); + if (shmid == -1) { + trc("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno); + return NULL; + } + + // Important note: + // It is very important that we, upon leaving this function, do not leave a shm segment alive. + // We must right after attaching it remove it from the system. System V shm segments are global and + // survive the process. + // So, from here on: Do not assert, do not return, until we have called shmctl(IPC_RMID) (A). + + struct shmid_ds shmbuf; + memset(&shmbuf, 0, sizeof(shmbuf)); + shmbuf.shm_pagesize = SIZE_64K; + if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) != 0) { + trcVerbose("Failed to set page size (need " UINTX_FORMAT " 64K pages) - shmctl failed with %d.", + size / SIZE_64K, errno); + // I want to know if this ever happens. + assert(false, "failed to set page size for shmat"); + } + + // Now attach the shared segment. + // Note that I attach with SHM_RND - which means that the requested address is rounded down, if + // needed, to the next lowest segment boundary. Otherwise the attach would fail if the address + // were not a segment boundary. + char* const addr = (char*) shmat(shmid, requested_addr, SHM_RND); + const int errno_shmat = errno; + + // (A) Right after shmat and before handing shmat errors delete the shm segment. + if (::shmctl(shmid, IPC_RMID, NULL) == -1) { + trc("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); + assert(false, "failed to remove shared memory segment!"); + } + + // Handle shmat error. If we failed to attach, just return. + if (addr == (char*)-1) { + trcVerbose("Failed to attach segment at " PTR_FORMAT " (%d).", requested_addr, errno_shmat); + return NULL; + } + + // Just for info: query the real page size. In case setting the page size did not + // work (see above), the system may have given us something other then 4K (LDR_CNTRL). + const size_t real_pagesize = os::Aix::query_pagesize(addr); + if (real_pagesize != shmbuf.shm_pagesize) { + trcVerbose("pagesize is, surprisingly, %h.", real_pagesize); + } + + if (addr) { + trcVerbose("shm-allocated " PTR_FORMAT " .. " PTR_FORMAT " (" UINTX_FORMAT " bytes, " UINTX_FORMAT " %s pages)", + addr, addr + size - 1, size, size/real_pagesize, describe_pagesize(real_pagesize)); + } else { + if (requested_addr != NULL) { + trcVerbose("failed to shm-allocate " UINTX_FORMAT " bytes at with address " PTR_FORMAT ".", size, requested_addr); + } else { + trcVerbose("failed to shm-allocate " UINTX_FORMAT " bytes at any address.", size); } - p = p->next(); - } - return NULL; -} - -// dump all information about all memory segments allocated with os::reserve_memory() -void shmbk_dump_info() { - tty->print_cr("-- shared mem bookkeeping (alive: %d segments, %llu bytes, " - "total reserves: %d total lookups: %d)", - g_shmbk_stats.nodes, g_shmbk_stats.bytes, g_shmbk_stats.reserves, g_shmbk_stats.lookups); - const ShmBkBlock* p = g_shmbk_list; - int i = 0; - while (p) { - p->print(tty); - p = p->next(); - i ++; - } -} - -#define LOCK_SHMBK { ThreadCritical _LOCK_SHMBK; -#define UNLOCK_SHMBK } + } + + // book-keeping + vmembk_add(addr, size, real_pagesize, VMEM_SHMATED); + assert0(is_aligned_to(addr, os::vm_page_size())); + + return addr; +} + +static bool release_shmated_memory(char* addr, size_t size) { + + trcVerbose("release_shmated_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + + bool rc = false; + + // TODO: is there a way to verify shm size without doing bookkeeping? + if (::shmdt(addr) != 0) { + trcVerbose("error (%d).", errno); + } else { + trcVerbose("ok."); + rc = true; + } + return rc; +} + +static bool uncommit_shmated_memory(char* addr, size_t size) { + trcVerbose("uncommit_shmated_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + + const bool rc = my_disclaim64(addr, size); + + if (!rc) { + trcVerbose("my_disclaim64(" PTR_FORMAT ", " UINTX_FORMAT ") failed.\n", addr, size); + return false; + } + return true; +} + +// Reserve memory via mmap. +// If is given, an attempt is made to attach at the given address. +// Failing that, memory is allocated at any address. +// If is given and is NULL, an attempt is made to +// allocate at an address aligned with the given alignment. Failing that, memory +// is aligned anywhere. +static char* reserve_mmaped_memory(size_t bytes, char* requested_addr, size_t alignment_hint) { + trcVerbose("reserve_mmaped_memory " UINTX_FORMAT " bytes, wishaddress " PTR_FORMAT ", " + "alignment_hint " UINTX_FORMAT "...", + bytes, requested_addr, alignment_hint); + + // If a wish address is given, but not aligned to 4K page boundary, mmap will fail. + if (requested_addr && !is_aligned_to(requested_addr, os::vm_page_size()) != 0) { + trcVerbose("Wish address " PTR_FORMAT " not aligned to page boundary.", requested_addr); + return NULL; + } + + // We must prevent anyone from attaching too close to the + // BRK because that may cause malloc OOM. + if (requested_addr != NULL && is_close_to_brk((address)requested_addr)) { + trcVerbose("Wish address " PTR_FORMAT " is too close to the BRK segment. " + "Will attach anywhere.", requested_addr); + // Act like the OS refused to attach there. + requested_addr = NULL; + } + + // Specify one or the other but not both. + assert0(!(requested_addr != NULL && alignment_hint > 0)); + + // In 64K mode, we claim the global page size (os::vm_page_size()) + // is 64K. This is one of the few points where that illusion may + // break, because mmap() will always return memory aligned to 4K. So + // we must ensure we only ever return memory aligned to 64k. + if (alignment_hint) { + alignment_hint = lcm(alignment_hint, os::vm_page_size()); + } else { + alignment_hint = os::vm_page_size(); + } + + // Size shall always be a multiple of os::vm_page_size (esp. in 64K mode). + const size_t size = align_size_up(bytes, os::vm_page_size()); + + // alignment: Allocate memory large enough to include an aligned range of the right size and + // cut off the leading and trailing waste pages. + assert0(alignment_hint != 0 && is_aligned_to(alignment_hint, os::vm_page_size())); // see above + const size_t extra_size = size + alignment_hint; + + // Note: MAP_SHARED (instead of MAP_PRIVATE) needed to be able to + // later use msync(MS_INVALIDATE) (see os::uncommit_memory). + int flags = MAP_ANONYMOUS | MAP_SHARED; + + // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what + // it means if wishaddress is given but MAP_FIXED is not set. + // + // Important! Behaviour differs depending on whether SPEC1170 mode is active or not. + // SPEC1170 mode active: behaviour like POSIX, MAP_FIXED will clobber existing mappings. + // SPEC1170 mode not active: behaviour, unlike POSIX, is that no existing mappings will + // get clobbered. + if (requested_addr != NULL) { + if (!os::Aix::xpg_sus_mode()) { // not SPEC1170 Behaviour + flags |= MAP_FIXED; + } + } + + char* addr = (char*)::mmap(requested_addr, extra_size, + PROT_READ|PROT_WRITE|PROT_EXEC, flags, -1, 0); + + if (addr == MAP_FAILED) { + trcVerbose("mmap(" PTR_FORMAT ", " UINTX_FORMAT ", ..) failed (%d)", requested_addr, size, errno); + return NULL; + } + + // Handle alignment. + char* const addr_aligned = (char *)align_ptr_up(addr, alignment_hint); + const size_t waste_pre = addr_aligned - addr; + char* const addr_aligned_end = addr_aligned + size; + const size_t waste_post = extra_size - waste_pre - size; + if (waste_pre > 0) { + ::munmap(addr, waste_pre); + } + if (waste_post > 0) { + ::munmap(addr_aligned_end, waste_post); + } + addr = addr_aligned; + + if (addr) { + trcVerbose("mmap-allocated " PTR_FORMAT " .. " PTR_FORMAT " (" UINTX_FORMAT " bytes)", + addr, addr + bytes, bytes); + } else { + if (requested_addr != NULL) { + trcVerbose("failed to mmap-allocate " UINTX_FORMAT " bytes at wish address " PTR_FORMAT ".", bytes, requested_addr); + } else { + trcVerbose("failed to mmap-allocate " UINTX_FORMAT " bytes at any address.", bytes); + } + } + + // bookkeeping + vmembk_add(addr, size, SIZE_4K, VMEM_MAPPED); + + // Test alignment, see above. + assert0(is_aligned_to(addr, os::vm_page_size())); + + return addr; +} + +static bool release_mmaped_memory(char* addr, size_t size) { + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + trcVerbose("release_mmaped_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + bool rc = false; + + if (::munmap(addr, size) != 0) { + trcVerbose("failed (%d)\n", errno); + rc = false; + } else { + trcVerbose("ok."); + rc = true; + } + + return rc; +} + +static bool uncommit_mmaped_memory(char* addr, size_t size) { + + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + trcVerbose("uncommit_mmaped_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + bool rc = false; + + // Uncommit mmap memory with msync MS_INVALIDATE. + if (::msync(addr, size, MS_INVALIDATE) != 0) { + trcVerbose("failed (%d)\n", errno); + rc = false; + } else { + trcVerbose("ok."); + rc = true; + } + + return rc; +} // End: shared memory bookkeeping //////////////////////////////////////////////////////////////////////////////////////////////////// int os::vm_page_size() { - // Seems redundant as all get out + // Seems redundant as all get out. assert(os::Aix::page_size() != -1, "must call os::init"); return os::Aix::page_size(); } @@ -2131,91 +2265,76 @@ return os::Aix::page_size(); } -int os::Aix::commit_memory_impl(char* addr, size_t size, bool exec) { - - // Commit is a noop. There is no explicit commit - // needed on AIX. Memory is committed when touched. - // - // Debug : check address range for validity -#ifdef ASSERT - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: " INTPTR_FORMAT "\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; - } else if (!block->containsRange(addr, size)) { - fprintf(stderr, "invalid range: " INTPTR_FORMAT " .. " INTPTR_FORMAT "\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid range"); - return false; - } - UNLOCK_SHMBK -#endif // ASSERT - - return 0; -} - -bool os::pd_commit_memory(char* addr, size_t size, bool exec) { - return os::Aix::commit_memory_impl(addr, size, exec) == 0; -} +#ifdef PRODUCT +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} +#endif void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, const char* mesg) { assert(mesg != NULL, "mesg must be specified"); - os::Aix::commit_memory_impl(addr, size, exec); -} - -int os::Aix::commit_memory_impl(char* addr, size_t size, - size_t alignment_hint, bool exec) { - return os::Aix::commit_memory_impl(addr, size, exec); -} - -bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, - bool exec) { - return os::Aix::commit_memory_impl(addr, size, alignment_hint, exec) == 0; + if (!pd_commit_memory(addr, size, exec)) { + // Add extra info in product mode for vm_exit_out_of_memory(): + PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + } +} + +bool os::pd_commit_memory(char* addr, size_t size, bool exec) { + + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + vmi->assert_is_valid_subrange(addr, size); + + trcVerbose("commit_memory [" PTR_FORMAT " - " PTR_FORMAT "].", addr, addr + size - 1); + + return true; +} + +bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { + return pd_commit_memory(addr, size, exec); } void os::pd_commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, bool exec, const char* mesg) { - os::Aix::commit_memory_impl(addr, size, alignment_hint, exec); + // Alignment_hint is ignored on this OS. + pd_commit_memory_or_exit(addr, size, exec, mesg); } bool os::pd_uncommit_memory(char* addr, size_t size) { - - // Delegate to ShmBkBlock class which knows how to uncommit its memory. - - bool rc = false; - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: 0x%p.\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; - } else if (!block->containsRange(addr, size)) { - fprintf(stderr, "invalid range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid range"); - return false; - } - rc = block->disclaim(addr, size); - UNLOCK_SHMBK - - if (Verbose && !rc) { - warning("failed to disclaim 0x%p .. 0x%p (0x%llX bytes).", addr, addr + size, size); - } - return rc; + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + // Dynamically do different things for mmap/shmat. + const vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + vmi->assert_is_valid_subrange(addr, size); + + if (vmi->type == VMEM_SHMATED) { + return uncommit_shmated_memory(addr, size); + } else { + return uncommit_mmaped_memory(addr, size); + } } bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::guard_memory(addr, size); + // Do not call this; no need to commit stack pages on AIX. + ShouldNotReachHere(); + return true; } bool os::remove_stack_guard_pages(char* addr, size_t size) { - return os::unguard_memory(addr, size); + // Do not call this; no need to commit stack pages on AIX. + ShouldNotReachHere(); + return true; } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2258,355 +2377,75 @@ return end; } -// Flags for reserve_shmatted_memory: -#define RESSHM_WISHADDR_OR_FAIL 1 -#define RESSHM_TRY_16M_PAGES 2 -#define RESSHM_16M_PAGES_OR_FAIL 4 - -// Result of reserve_shmatted_memory: -struct shmatted_memory_info_t { - char* addr; - size_t pagesize; - bool pinned; -}; - -// Reserve a section of shmatted memory. -// params: -// bytes [in]: size of memory, in bytes -// requested_addr [in]: wish address. -// NULL = no wish. -// If RESSHM_WISHADDR_OR_FAIL is set in flags and wish address cannot -// be obtained, function will fail. Otherwise wish address is treated as hint and -// another pointer is returned. -// flags [in]: some flags. Valid flags are: -// RESSHM_WISHADDR_OR_FAIL - fail if wish address is given and cannot be obtained. -// RESSHM_TRY_16M_PAGES - try to allocate from 16M page pool -// (requires UseLargePages and Use16MPages) -// RESSHM_16M_PAGES_OR_FAIL - if you cannot allocate from 16M page pool, fail. -// Otherwise any other page size will do. -// p_info [out] : holds information about the created shared memory segment. -static bool reserve_shmatted_memory(size_t bytes, char* requested_addr, int flags, shmatted_memory_info_t* p_info) { - - assert(p_info, "parameter error"); - - // init output struct. - p_info->addr = NULL; - - // neither should we be here for EXTSHM=ON. - if (os::Aix::extshm()) { - ShouldNotReachHere(); - } - - // extract flags. sanity checks. - const bool wishaddr_or_fail = - flags & RESSHM_WISHADDR_OR_FAIL; - const bool try_16M_pages = - flags & RESSHM_TRY_16M_PAGES; - const bool f16M_pages_or_fail = - flags & RESSHM_16M_PAGES_OR_FAIL; - - // first check: if a wish address is given and it is mandatory, but not aligned to segment boundary, - // shmat will fail anyway, so save some cycles by failing right away - if (requested_addr && ((uintptr_t)requested_addr % SIZE_256M == 0)) { - if (wishaddr_or_fail) { - return false; - } else { - requested_addr = NULL; - } - } - - char* addr = NULL; - - // Align size of shm up to the largest possible page size, to avoid errors later on when we try to change - // pagesize dynamically. - const size_t size = align_size_up(bytes, SIZE_16M); - - // reserve the shared segment - int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR); - if (shmid == -1) { - warning("shmget(.., %lld, ..) failed (errno: %d).", size, errno); - return false; - } - - // Important note: - // It is very important that we, upon leaving this function, do not leave a shm segment alive. - // We must right after attaching it remove it from the system. System V shm segments are global and - // survive the process. - // So, from here on: Do not assert. Do not return. Always do a "goto cleanup_shm". - - // try forcing the page size - size_t pagesize = -1; // unknown so far - - if (UseLargePages) { - - struct shmid_ds shmbuf; - memset(&shmbuf, 0, sizeof(shmbuf)); - - // First, try to take from 16M page pool if... - if (os::Aix::can_use_16M_pages() // we can ... - && Use16MPages // we are not explicitly forbidden to do so (-XX:-Use16MPages).. - && try_16M_pages) { // caller wants us to. - shmbuf.shm_pagesize = SIZE_16M; - if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) == 0) { - pagesize = SIZE_16M; - } else { - warning("Failed to allocate %d 16M pages. 16M page pool might be exhausted. (shmctl failed with %d)", - size / SIZE_16M, errno); - if (f16M_pages_or_fail) { - goto cleanup_shm; - } - } - } - - // Nothing yet? Try setting 64K pages. Note that I never saw this fail, but in theory it might, - // because the 64K page pool may also be exhausted. - if (pagesize == -1) { - shmbuf.shm_pagesize = SIZE_64K; - if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) == 0) { - pagesize = SIZE_64K; - } else { - warning("Failed to allocate %d 64K pages. (shmctl failed with %d)", - size / SIZE_64K, errno); - // here I give up. leave page_size -1 - later, after attaching, we will query the - // real page size of the attached memory. (in theory, it may be something different - // from 4K if LDR_CNTRL SHM_PSIZE is set) - } - } - } - - // sanity point - assert(pagesize == -1 || pagesize == SIZE_16M || pagesize == SIZE_64K, "wrong page size"); - - // Now attach the shared segment. - addr = (char*) shmat(shmid, requested_addr, 0); - if (addr == (char*)-1) { - // How to handle attach failure: - // If it failed for a specific wish address, tolerate this: in that case, if wish address was - // mandatory, fail, if not, retry anywhere. - // If it failed for any other reason, treat that as fatal error. - addr = NULL; - if (requested_addr) { - if (wishaddr_or_fail) { - goto cleanup_shm; - } else { - addr = (char*) shmat(shmid, NULL, 0); - if (addr == (char*)-1) { // fatal - addr = NULL; - warning("shmat failed (errno: %d)", errno); - goto cleanup_shm; - } - } - } else { // fatal - addr = NULL; - warning("shmat failed (errno: %d)", errno); - goto cleanup_shm; - } - } - - // sanity point - assert(addr && addr != (char*) -1, "wrong address"); - - // after successful Attach remove the segment - right away. - if (::shmctl(shmid, IPC_RMID, NULL) == -1) { - warning("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); - guarantee(false, "failed to remove shared memory segment!"); - } - shmid = -1; - - // query the real page size. In case setting the page size did not work (see above), the system - // may have given us something other then 4K (LDR_CNTRL) - { - const size_t real_pagesize = os::Aix::query_pagesize(addr); - if (pagesize != -1) { - assert(pagesize == real_pagesize, "unexpected pagesize after shmat"); - } else { - pagesize = real_pagesize; - } - } - - // Now register the reserved block with internal book keeping. - LOCK_SHMBK - const bool pinned = pagesize >= SIZE_16M ? true : false; - ShmBkShmatedBlock* const p_block = new ShmBkShmatedBlock(AddrRange(addr, size), pagesize, pinned); - assert(p_block, ""); - shmbk_register(p_block); - UNLOCK_SHMBK - -cleanup_shm: - - // if we have not done so yet, remove the shared memory segment. This is very important. - if (shmid != -1) { - if (::shmctl(shmid, IPC_RMID, NULL) == -1) { - warning("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); - guarantee(false, "failed to remove shared memory segment!"); - } - shmid = -1; - } - - // trace - if (Verbose && !addr) { - if (requested_addr != NULL) { - warning("failed to shm-allocate 0x%llX bytes at wish address 0x%p.", size, requested_addr); - } else { - warning("failed to shm-allocate 0x%llX bytes at any address.", size); - } - } - - // hand info to caller - if (addr) { - p_info->addr = addr; - p_info->pagesize = pagesize; - p_info->pinned = pagesize == SIZE_16M ? true : false; - } - - // sanity test: - if (requested_addr && addr && wishaddr_or_fail) { - guarantee(addr == requested_addr, "shmat error"); - } - - // just one more test to really make sure we have no dangling shm segments. - guarantee(shmid == -1, "dangling shm segments"); - - return addr ? true : false; - -} // end: reserve_shmatted_memory - -// Reserve memory using mmap. Behaves the same as reserve_shmatted_memory(): -// will return NULL in case of an error. -static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { - - // if a wish address is given, but not aligned to 4K page boundary, mmap will fail. - if (requested_addr && ((uintptr_t)requested_addr % os::vm_page_size() != 0)) { - warning("Wish address 0x%p not aligned to page boundary.", requested_addr); - return NULL; - } - - const size_t size = align_size_up(bytes, SIZE_4K); - - // Note: MAP_SHARED (instead of MAP_PRIVATE) needed to be able to - // msync(MS_INVALIDATE) (see os::uncommit_memory) - int flags = MAP_ANONYMOUS | MAP_SHARED; - - // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what - // it means if wishaddress is given but MAP_FIXED is not set. - // - // Note however that this changes semantics in SPEC1170 mode insofar as MAP_FIXED - // clobbers the address range, which is probably not what the caller wants. That's - // why I assert here (again) that the SPEC1170 compat mode is off. - // If we want to be able to run under SPEC1170, we have to do some porting and - // testing. - if (requested_addr != NULL) { - assert(!os::Aix::xpg_sus_mode(), "SPEC1170 mode not allowed."); - flags |= MAP_FIXED; - } - - char* addr = (char*)::mmap(requested_addr, size, PROT_READ|PROT_WRITE|PROT_EXEC, flags, -1, 0); - - if (addr == MAP_FAILED) { - // attach failed: tolerate for specific wish addresses. Not being able to attach - // anywhere is a fatal error. - if (requested_addr == NULL) { - // It's ok to fail here if the machine has not enough memory. - warning("mmap(NULL, 0x%llX, ..) failed (%d)", size, errno); - } - addr = NULL; - goto cleanup_mmap; - } - - // If we did request a specific address and that address was not available, fail. - if (addr && requested_addr) { - guarantee(addr == requested_addr, "unexpected"); - } - - // register this mmap'ed segment with book keeping - LOCK_SHMBK - ShmBkMappedBlock* const p_block = new ShmBkMappedBlock(AddrRange(addr, size)); - assert(p_block, ""); - shmbk_register(p_block); - UNLOCK_SHMBK - -cleanup_mmap: - - // trace - if (Verbose) { - if (addr) { - fprintf(stderr, "mmap-allocated 0x%p .. 0x%p (0x%llX bytes)\n", addr, addr + bytes, bytes); - } - else { - if (requested_addr != NULL) { - warning("failed to mmap-allocate 0x%llX bytes at wish address 0x%p.", bytes, requested_addr); - } else { - warning("failed to mmap-allocate 0x%llX bytes at any address.", bytes); - } - } - } - - return addr; - -} // end: reserve_mmaped_memory - // Reserves and attaches a shared memory segment. // Will assert if a wish address is given and could not be obtained. char* os::pd_reserve_memory(size_t bytes, char* requested_addr, size_t alignment_hint) { - return os::attempt_reserve_memory_at(bytes, requested_addr); + + // All other Unices do a mmap(MAP_FIXED) if the addr is given, + // thereby clobbering old mappings at that place. That is probably + // not intended, never used and almost certainly an error were it + // ever be used this way (to try attaching at a specified address + // without clobbering old mappings an alternate API exists, + // os::attempt_reserve_memory_at()). + // Instead of mimicking the dangerous coding of the other platforms, here I + // just ignore the request address (release) or assert(debug). + assert0(requested_addr == NULL); + + // Always round to os::vm_page_size(), which may be larger than 4K. + bytes = align_size_up(bytes, os::vm_page_size()); + const size_t alignment_hint0 = + alignment_hint ? align_size_up(alignment_hint, os::vm_page_size()) : 0; + + // In 4K mode always use mmap. + // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. + if (os::vm_page_size() == SIZE_4K) { + return reserve_mmaped_memory(bytes, requested_addr, alignment_hint); + } else { + if (bytes >= Use64KPagesThreshold) { + return reserve_shmated_memory(bytes, requested_addr, alignment_hint); + } else { + return reserve_mmaped_memory(bytes, requested_addr, alignment_hint); + } + } } bool os::pd_release_memory(char* addr, size_t size) { - // delegate to ShmBkBlock class which knows how to uncommit its memory. + // Dynamically do different things for mmap/shmat. + vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + + // Always round to os::vm_page_size(), which may be larger than 4K. + size = align_size_up(size, os::vm_page_size()); + addr = (char *)align_ptr_up(addr, os::vm_page_size()); bool rc = false; - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: 0x%p.\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; + bool remove_bookkeeping = false; + if (vmi->type == VMEM_SHMATED) { + // For shmatted memory, we do: + // - If user wants to release the whole range, release the memory (shmdt). + // - If user only wants to release a partial range, uncommit (disclaim) that + // range. That way, at least, we do not use memory anymore (bust still page + // table space). + vmi->assert_is_valid_subrange(addr, size); + if (addr == vmi->addr && size == vmi->size) { + rc = release_shmated_memory(addr, size); + remove_bookkeeping = true; + } else { + rc = uncommit_shmated_memory(addr, size); } - else if (!block->isSameRange(addr, size)) { - if (block->getType() == ShmBkBlock::MMAP) { - // Release only the same range or a the beginning or the end of a range. - if (block->base() == addr && size < block->size()) { - ShmBkMappedBlock* const b = new ShmBkMappedBlock(AddrRange(block->base() + size, block->size() - size)); - assert(b, ""); - shmbk_register(b); - block->setAddrRange(AddrRange(addr, size)); - } - else if (addr > block->base() && addr + size == block->base() + block->size()) { - ShmBkMappedBlock* const b = new ShmBkMappedBlock(AddrRange(block->base(), block->size() - size)); - assert(b, ""); - shmbk_register(b); - block->setAddrRange(AddrRange(addr, size)); - } - else { - fprintf(stderr, "invalid mmap range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid mmap range"); - return false; - } - } - else { - // Release only the same range. No partial release allowed. - // Soften the requirement a bit, because the user may think he owns a smaller size - // than the block is due to alignment etc. - if (block->base() != addr || block->size() < size) { - fprintf(stderr, "invalid shmget range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid shmget range"); - return false; - } - } - } - rc = block->release(); - assert(rc, "release failed"); - // remove block from bookkeeping - shmbk_unregister(block); - delete block; - UNLOCK_SHMBK - - if (!rc) { - warning("failed to released %lu bytes at 0x%p", size, addr); + } else { + // User may unmap partial regions but region has to be fully contained. +#ifdef ASSERT + vmi->assert_is_valid_subrange(addr, size); +#endif + rc = release_mmaped_memory(addr, size); + remove_bookkeeping = true; + } + + // update bookkeeping + if (rc && remove_bookkeeping) { + vmembk_remove(vmi); } return rc; @@ -2687,46 +2526,8 @@ // Enable large page support if OS allows that. void os::large_page_init() { - - // Note: os::Aix::query_multipage_support must run first. - - if (!UseLargePages) { - return; - } - - if (!Aix::can_use_64K_pages()) { - assert(!Aix::can_use_16M_pages(), "64K is a precondition for 16M."); - UseLargePages = false; - return; - } - - if (!Aix::can_use_16M_pages() && Use16MPages) { - fprintf(stderr, "Cannot use 16M pages. Please ensure that there is a 16M page pool " - " and that the VM runs with CAP_BYPASS_RAC_VMM and CAP_PROPAGATE capabilities.\n"); - } - - // Do not report 16M page alignment as part of os::_page_sizes if we are - // explicitly forbidden from using 16M pages. Doing so would increase the - // alignment the garbage collector calculates with, slightly increasing - // heap usage. We should only pay for 16M alignment if we really want to - // use 16M pages. - if (Use16MPages && Aix::can_use_16M_pages()) { - _large_page_size = SIZE_16M; - _page_sizes[0] = SIZE_16M; - _page_sizes[1] = SIZE_64K; - _page_sizes[2] = SIZE_4K; - _page_sizes[3] = 0; - } else if (Aix::can_use_64K_pages()) { - _large_page_size = SIZE_64K; - _page_sizes[0] = SIZE_64K; - _page_sizes[1] = SIZE_4K; - _page_sizes[2] = 0; - } - - if (Verbose) { - ("Default large page size is 0x%llX.", _large_page_size); - } -} // end: os::large_page_init() + return; // Nothing to do. See query_multipage_support and friends. +} char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { // "exec" is passed in but not used. Creating the shared image for @@ -2736,7 +2537,7 @@ } bool os::release_memory_special(char* base, size_t bytes) { - // detaching the SHM segment will also delete it, see reserve_memory_special() + // Detaching the SHM segment will also delete it, see reserve_memory_special(). Unimplemented(); return false; } @@ -2746,40 +2547,32 @@ } bool os::can_commit_large_page_memory() { - // Well, sadly we cannot commit anything at all (see comment in - // os::commit_memory) but we claim to so we can make use of large pages - return true; + // Does not matter, we do not support huge pages. + return false; } bool os::can_execute_large_page_memory() { - // We can do that - return true; + // Does not matter, we do not support huge pages. + return false; } // Reserve memory at an arbitrary address, only if that area is // available (and not reserved for something else). char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { - - bool use_mmap = false; - - // mmap: smaller graining, no large page support - // shm: large graining (256M), large page support, limited number of shm segments - // - // Prefer mmap wherever we either do not need large page support or have OS limits - - if (!UseLargePages || bytes < SIZE_16M) { - use_mmap = true; - } - char* addr = NULL; - if (use_mmap) { - addr = reserve_mmaped_memory(bytes, requested_addr); + + // Always round to os::vm_page_size(), which may be larger than 4K. + bytes = align_size_up(bytes, os::vm_page_size()); + + // In 4K mode always use mmap. + // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. + if (os::vm_page_size() == SIZE_4K) { + return reserve_mmaped_memory(bytes, requested_addr, 0); } else { - // shmat: wish address is mandatory, and do not try 16M pages here. - shmatted_memory_info_t info; - const int flags = RESSHM_WISHADDR_OR_FAIL; - if (reserve_shmatted_memory(bytes, requested_addr, flags, &info)) { - addr = info.addr; + if (bytes >= Use64KPagesThreshold) { + return reserve_shmated_memory(bytes, requested_addr, 0); + } else { + return reserve_mmaped_memory(bytes, requested_addr, 0); } } @@ -3614,18 +3407,89 @@ // This is called _before_ the most of global arguments have been parsed. void os::init(void) { // This is basic, we want to know if that ever changes. - // (shared memory boundary is supposed to be a 256M aligned) + // (Shared memory boundary is supposed to be a 256M aligned.) assert(SHMLBA == ((uint64_t)0x10000000ULL)/*256M*/, "unexpected"); // First off, we need to know whether we run on AIX or PASE, and // the OS level we run on. os::Aix::initialize_os_info(); - // Scan environment (SPEC1170 behaviour, etc) + // Scan environment (SPEC1170 behaviour, etc). os::Aix::scan_environment(); // Check which pages are supported by AIX. - os::Aix::query_multipage_support(); + query_multipage_support(); + + // Act like we only have one page size by eliminating corner cases which + // we did not support very well anyway. + // We have two input conditions: + // 1) Data segment page size. This is controlled by linker setting (datapsize) on the + // launcher, and/or by LDR_CNTRL environment variable. The latter overrules the linker + // setting. + // Data segment page size is important for us because it defines the thread stack page + // size, which is needed for guard page handling, stack banging etc. + // 2) The ability to allocate 64k pages dynamically. If this is a given, java heap can + // and should be allocated with 64k pages. + // + // So, we do the following: + // LDR_CNTRL can_use_64K_pages_dynamically what we do remarks + // 4K no 4K old systems (aix 5.2, as/400 v5r4) or new systems with AME activated + // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings + // 64k no --- AIX 5.2 ? --- + // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) + + // We explicitly leave no option to change page size, because only upgrading would work, + // not downgrading (if stack page size is 64k you cannot pretend its 4k). + + if (g_multipage_support.datapsize == SIZE_4K) { + // datapsize = 4K. Data segment, thread stacks are 4K paged. + if (g_multipage_support.can_use_64K_pages) { + // .. but we are able to use 64K pages dynamically. + // This would be typical for java launchers which are not linked + // with datapsize=64K (like, any other launcher but our own). + // + // In this case it would be smart to allocate the java heap with 64K + // to get the performance benefit, and to fake 64k pages for the + // data segment (when dealing with thread stacks). + // + // However, leave a possibility to downgrade to 4K, using + // -XX:-Use64KPages. + if (Use64KPages) { + trcVerbose("64K page mode (faked for data segment)"); + Aix::_page_size = SIZE_64K; + } else { + trcVerbose("4K page mode (Use64KPages=off)"); + Aix::_page_size = SIZE_4K; + } + } else { + // .. and not able to allocate 64k pages dynamically. Here, just + // fall back to 4K paged mode and use mmap for everything. + trcVerbose("4K page mode"); + Aix::_page_size = SIZE_4K; + FLAG_SET_ERGO(bool, Use64KPages, false); + } + } else { + // datapsize = 64k. Data segment, thread stacks are 64k paged. + // This normally means that we can allocate 64k pages dynamically. + // (There is one special case where this may be false: EXTSHM=on. + // but we decided to not support that mode). + assert0(g_multipage_support.can_use_64K_pages); + Aix::_page_size = SIZE_64K; + trcVerbose("64K page mode"); + FLAG_SET_ERGO(bool, Use64KPages, true); + } + + // Short-wire stack page size to base page size; if that works, we just remove + // that stack page size altogether. + Aix::_stack_page_size = Aix::_page_size; + + // For now UseLargePages is just ignored. + FLAG_SET_ERGO(bool, UseLargePages, false); + _page_sizes[0] = 0; + _large_page_size = -1; + + // debug trace + trcVerbose("os::vm_page_size %s\n", describe_pagesize(os::vm_page_size())); // Next, we need to initialize libo4 and libperfstat libraries. if (os::Aix::on_pase()) { @@ -3643,34 +3507,6 @@ // need libperfstat etc. os::Aix::initialize_system_info(); - // Initialize large page support. - if (UseLargePages) { - os::large_page_init(); - if (!UseLargePages) { - // initialize os::_page_sizes - _page_sizes[0] = Aix::page_size(); - _page_sizes[1] = 0; - if (Verbose) { - fprintf(stderr, "Large Page initialization failed: setting UseLargePages=0.\n"); - } - } - } else { - // initialize os::_page_sizes - _page_sizes[0] = Aix::page_size(); - _page_sizes[1] = 0; - } - - // debug trace - if (Verbose) { - fprintf(stderr, "os::vm_page_size 0x%llX\n", os::vm_page_size()); - fprintf(stderr, "os::large_page_size 0x%llX\n", os::large_page_size()); - fprintf(stderr, "os::_page_sizes = ( "); - for (int i = 0; _page_sizes[i]; i ++) { - fprintf(stderr, " %s ", describe_pagesize(_page_sizes[i])); - } - fprintf(stderr, ")\n"); - } - _initial_pid = getpid(); clock_tics_per_sec = sysconf(_SC_CLK_TCK); @@ -3683,6 +3519,15 @@ Aix::_main_thread = pthread_self(); initial_time_count = os::elapsed_counter(); + + // If the pagesize of the VM is greater than 8K determine the appropriate + // number of initial guard pages. The user can change this with the + // command line arguments, if needed. + if (vm_page_size() > (int)Aix::vm_default_page_size()) { + StackYellowPages = 1; + StackRedPages = 1; + StackShadowPages = round_to((StackShadowPages*Aix::vm_default_page_size()), vm_page_size()) / vm_page_size(); + } } // This is called _after_ the global arguments have been parsed. @@ -3701,7 +3546,7 @@ const int prot = PROT_READ; const int flags = MAP_PRIVATE|MAP_ANONYMOUS; - // use optimized addresses for the polling page, + // Use optimized addresses for the polling page, // e.g. map it to a special 32-bit address. if (OptimizePollingPageLocation) { // architecture-specific list of address wishes: @@ -3723,7 +3568,7 @@ // iterate over the list of address wishes: for (int i=0; iprint("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page); + } #endif } @@ -3781,16 +3627,18 @@ // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Aix::min_stack_allowed = MAX2(os::Aix::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages + - 2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::page_size()); + (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Aix::page_size() + + (2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::vm_default_page_size()); + + os::Aix::min_stack_allowed = align_size_up(os::Aix::min_stack_allowed, os::Aix::page_size()); size_t threadStackSizeInBytes = ThreadStackSize * K; if (threadStackSizeInBytes != 0 && threadStackSizeInBytes < os::Aix::min_stack_allowed) { - tty->print_cr("\nThe stack size specified is too small, " - "Specify at least %dk", - os::Aix::min_stack_allowed / K); - return JNI_ERR; + tty->print_cr("\nThe stack size specified is too small, " + "Specify at least %dk", + os::Aix::min_stack_allowed / K); + return JNI_ERR; } // Make the stack size a multiple of the page size so that @@ -3801,7 +3649,7 @@ Aix::libpthread_init(); if (MaxFDLimit) { - // set the number of file descriptors to max. print out error + // Set the number of file descriptors to max. print out error // if getrlimit/setrlimit fails but continue regardless. struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); @@ -3819,12 +3667,12 @@ } if (PerfAllowAtExitRegistration) { - // only register atexit functions if PerfAllowAtExitRegistration is set. - // atexit functions can be delayed until process exit time, which + // Only register atexit functions if PerfAllowAtExitRegistration is set. + // Atexit functions can be delayed until process exit time, which // can be problematic for embedded VM situations. Embedded VMs should // call DestroyJavaVM() to assure that VM resources are released. - // note: perfMemory_exit_helper atexit function may be removed in + // Note: perfMemory_exit_helper atexit function may be removed in // the future if the appropriate cleanup code can be added to the // VM_Exit VMOperation's doit method. if (atexit(perfMemory_exit_helper) != 0) { @@ -4146,8 +3994,10 @@ if (read_only) { prot = PROT_READ; + flags = MAP_SHARED; } else { prot = PROT_READ | PROT_WRITE; + flags = MAP_PRIVATE; } if (allow_exec) { @@ -4158,7 +4008,12 @@ flags |= MAP_FIXED; } - char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags, + // Allow anonymous mappings if 'fd' is -1. + if (fd == -1) { + flags |= MAP_ANONYMOUS; + } + + char* mapped_address = (char*)::mmap(addr, (size_t)bytes, prot, flags, fd, file_offset); if (mapped_address == MAP_FAILED) { return NULL; @@ -4416,7 +4271,7 @@ if (Verbose) { fprintf(stderr, "EXTSHM=%s.\n", p ? p : ""); } - if (p && strcmp(p, "ON") == 0) { + if (p && strcasecmp(p, "ON") == 0) { fprintf(stderr, "Unsupported setting: EXTSHM=ON. Large Page support will be disabled.\n"); _extshm = 1; } else { @@ -4477,16 +4332,13 @@ ///////////////////////////////////////////////////////////////////////////// // thread stack -// function to query the current stack size using pthread_getthrds_np -// -// ! do not change anything here unless you know what you are doing ! -static void query_stack_dimensions(address* p_stack_base, size_t* p_stack_size) { - +// Function to query the current stack size using pthread_getthrds_np. +static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size) { // This only works when invoked on a pthread. As we agreed not to use - // primordial threads anyway, I assert here + // primordial threads anyway, I assert here. guarantee(!os::Aix::is_primordial_thread(), "not allowed on the primordial thread"); - // information about this api can be found (a) in the pthread.h header and + // Information about this api can be found (a) in the pthread.h header and // (b) in http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/pthread_getthrds_np.htm // // The use of this API to find out the current stack is kind of undefined. @@ -4497,57 +4349,72 @@ pthread_t tid = pthread_self(); struct __pthrdsinfo pinfo; - char dummy[1]; // we only need this to satisfy the api and to not get E + char dummy[1]; // We only need this to satisfy the api and to not get E. int dummy_size = sizeof(dummy); memset(&pinfo, 0, sizeof(pinfo)); - const int rc = pthread_getthrds_np (&tid, PTHRDSINFO_QUERY_ALL, &pinfo, - sizeof(pinfo), dummy, &dummy_size); + const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &pinfo, + sizeof(pinfo), dummy, &dummy_size); if (rc != 0) { - fprintf(stderr, "pthread_getthrds_np failed (%d)\n", rc); - guarantee(0, "pthread_getthrds_np failed"); - } - - guarantee(pinfo.__pi_stackend, "returned stack base invalid"); - - // the following can happen when invoking pthread_getthrds_np on a pthread running on a user provided stack - // (when handing down a stack to pthread create, see pthread_attr_setstackaddr). + assert0(false); + trcVerbose("pthread_getthrds_np failed (%d)", rc); + return false; + } + guarantee0(pinfo.__pi_stackend); + + // The following can happen when invoking pthread_getthrds_np on a pthread running + // on a user provided stack (when handing down a stack to pthread create, see + // pthread_attr_setstackaddr). // Not sure what to do here - I feel inclined to forbid this use case completely. - guarantee(pinfo.__pi_stacksize, "returned stack size invalid"); - - // On AIX, stacks are not necessarily page aligned so round the base and size accordingly + guarantee0(pinfo.__pi_stacksize); + + // Note: the pthread stack on AIX seems to look like this: + // + // --------------------- real base ? at page border ? + // + // pthread internal data, like ~2K, see also + // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/thread_supp_tun_params.htm + // + // --------------------- __pi_stackend - not page aligned, (xxxxF890) + // + // stack + // .... + // + // stack + // + // --------------------- __pi_stackend - __pi_stacksize + // + // padding due to AIX guard pages (?) see AIXTHREAD_GUARDPAGES + // --------------------- __pi_stackaddr (page aligned if AIXTHREAD_GUARDPAGES > 0) + // + // AIX guard pages (?) + // + + // So, the safe thing to do is to use the area from __pi_stackend to __pi_stackaddr; + // __pi_stackend however is almost never page aligned. + // + if (p_stack_base) { - (*p_stack_base) = (address) align_size_up((intptr_t)pinfo.__pi_stackend, os::Aix::stack_page_size()); + (*p_stack_base) = (address) (pinfo.__pi_stackend); } if (p_stack_size) { - (*p_stack_size) = pinfo.__pi_stacksize - os::Aix::stack_page_size(); - } - -#ifndef PRODUCT - if (Verbose) { - fprintf(stderr, - "query_stack_dimensions() -> real stack_base=" INTPTR_FORMAT ", real stack_addr=" INTPTR_FORMAT - ", real stack_size=" INTPTR_FORMAT - ", stack_base=" INTPTR_FORMAT ", stack_size=" INTPTR_FORMAT "\n", - (intptr_t)pinfo.__pi_stackend, (intptr_t)pinfo.__pi_stackaddr, pinfo.__pi_stacksize, - (intptr_t)align_size_up((intptr_t)pinfo.__pi_stackend, os::Aix::stack_page_size()), - pinfo.__pi_stacksize - os::Aix::stack_page_size()); - } -#endif - -} // end query_stack_dimensions - -// get the current stack base from the OS (actually, the pthread library) + (*p_stack_size) = pinfo.__pi_stackend - pinfo.__pi_stackaddr; + } + + return true; +} + +// Get the current stack base from the OS (actually, the pthread library). address os::current_stack_base() { address p; query_stack_dimensions(&p, 0); return p; } -// get the current stack size from the OS (actually, the pthread library) +// Get the current stack size from the OS (actually, the pthread library). size_t os::current_stack_size() { size_t s; query_stack_dimensions(0, &s); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/os_aix.hpp --- a/hotspot/src/os/aix/vm/os_aix.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/os_aix.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,9 @@ friend class os; // For signal-chaining - // highest so far (AIX 5.2) is SIGSAK (63) + // highest so far (AIX 5.2 - 6.1) is SIGSAK (63) #define MAXSIGNUM 63 - // length of strings included in the libperfstat structures + // Length of strings included in the libperfstat structures. #define IDENTIFIER_LENGTH 64 static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions @@ -111,22 +111,6 @@ // (should be LDR_CNTRL DATAPSIZE because stack is allocated on heap by pthread lib) static int _stack_page_size; - // Default shm page size. Read: what page size shared memory will be backed - // with if no page size was set explicitly using shmctl(SHM_PAGESIZE). - // Should be LDR_CNTRL SHMPSIZE. - static size_t _shm_default_page_size; - - // True if sys V shm can be used with 64K pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). Should be true for AIX 53 and - // newer / PASE V6R1 and newer. (0 or 1, -1 if not initialized) - static int _can_use_64K_pages; - - // True if sys V shm can be used with 16M pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). Only true on AIX 5.3 and - // newer, if the system was set up to use 16M pages and the - // jvm has enough user rights. (0 or 1, -1 if not initialized) - static int _can_use_16M_pages; - static julong available_memory(); static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); @@ -135,10 +119,6 @@ // one of Aix::on_pase(), Aix::os_version(). static void initialize_os_info(); - static int commit_memory_impl(char* addr, size_t bytes, bool exec); - static int commit_memory_impl(char* addr, size_t bytes, - size_t alignment_hint, bool exec); - // Scan environment for important settings which might effect the // VM. Trace out settings. Warn about invalid settings and/or // correct them. @@ -146,10 +126,6 @@ // Must run after os::Aix::initialue_os_info(). static void scan_environment(); - // Retrieve information about multipage size support. Will initialize - // _page_size, _stack_page_size, _can_use_64K_pages/_can_use_16M_pages - static void query_multipage_support(); - // Initialize libo4 (on PASE) and libperfstat (on AIX). Call this // before relying on functions from either lib, e.g. Aix::get_meminfo(). static void initialize_libo4(); @@ -187,27 +163,8 @@ return _stack_page_size; } - // default shm page size. Read: what page size shared memory - // will be backed with if no page size was set explicitly using shmctl(SHM_PAGESIZE). - // Should be LDR_CNTRL SHMPSIZE. - static int shm_default_page_size(void) { - assert(_shm_default_page_size != -1, "not initialized"); - return _shm_default_page_size; - } - - // Return true if sys V shm can be used with 64K pages dynamically - // (via shmctl(.. SHM_PAGESIZE..). - static bool can_use_64K_pages () { - assert(_can_use_64K_pages != -1, "not initialized"); - return _can_use_64K_pages == 1 ? true : false; - } - - // Return true if sys V shm can be used with 16M pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). - static bool can_use_16M_pages () { - assert(_can_use_16M_pages != -1, "not initialized"); - return _can_use_16M_pages == 1 ? true : false; - } + // This is used to scale stack space (guard pages etc.). The name is somehow misleading. + static int vm_default_page_size(void ) { return 8*K; } static address ucontext_get_pc(const ucontext_t* uc); static intptr_t* ucontext_get_sp(ucontext_t* uc); @@ -269,6 +226,11 @@ return _os_version; } + // Convenience method: returns true if running on PASE V5R4 or older. + static bool on_pase_V5R4_or_older() { + return on_pase() && os_version() <= 0x0504; + } + // Convenience method: returns true if running on AIX 5.3 or older. static bool on_aix_53_or_older() { return on_aix() && os_version() <= 0x0503; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/os_aix.inline.hpp --- a/hotspot/src/os/aix/vm/os_aix.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ return pthread_getspecific((pthread_key_t)index); } -// File names are case-sensitive on windows only +// File names are case-sensitive on windows only. inline int os::file_name_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); } @@ -53,18 +53,19 @@ return true; } +// Whether or not calling code should/can commit/uncommit stack pages +// before guarding them. Answer for AIX is definitly no, because memory +// is automatically committed on touch. inline bool os::allocate_stack_guard_pages() { assert(uses_stack_guard_pages(), "sanity check"); - return true; + return false; } - // On Aix, reservations are made on a page by page basis, nothing to do. inline void os::pd_split_reserved_memory(char *base, size_t size, size_t split, bool realloc) { } - // Bang the shadow pages if they need to be touched to be mapped. inline void os::bang_stack_shadow_pages() { } @@ -75,15 +76,13 @@ inline const int os::default_file_open_flags() { return 0;} -inline DIR* os::opendir(const char* dirname) -{ +inline DIR* os::opendir(const char* dirname) { assert(dirname != NULL, "just checking"); return ::opendir(dirname); } -inline int os::readdir_buf_size(const char *path) -{ - // according to aix sys/limits, NAME_MAX must be retrieved at runtime. */ +inline int os::readdir_buf_size(const char *path) { + // According to aix sys/limits, NAME_MAX must be retrieved at runtime. const long my_NAME_MAX = pathconf(path, _PC_NAME_MAX); return my_NAME_MAX + sizeof(dirent) + 1; } @@ -104,8 +103,7 @@ return ::ftruncate64(fd, length); } -inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) -{ +inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) { dirent* p; int status; assert(dirp != NULL, "just checking"); @@ -174,11 +172,11 @@ RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags)); } -inline int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { +inline int os::raw_send(int fd, char *buf, size_t nBytes, uint flags) { return os::send(fd, buf, nBytes, flags); } -inline int os::connect(int fd, struct sockaddr* him, socklen_t len) { +inline int os::connect(int fd, struct sockaddr *him, socklen_t len) { RESTARTABLE_RETURN_INT(::connect(fd, him, len)); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/perfMemory_aix.cpp --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -797,7 +797,7 @@ // Close the directory and reset the current working directory. close_directory_secure_cwd(dirp, saved_cwd_fd); - FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + FREE_C_HEAP_ARRAY(char, dbuf); } // Make the user specific temporary directory. Returns true if @@ -1164,9 +1164,9 @@ // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname, mtInternal); + FREE_C_HEAP_ARRAY(char, dirname); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser, mtInternal); + FREE_C_HEAP_ARRAY(char, luser); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os/aix/vm/porting_aix.hpp --- a/hotspot/src/os/aix/vm/porting_aix.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os/aix/vm/porting_aix.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,18 @@ * */ +#ifndef OS_AIX_VM_PORTING_AIX_HPP +#define OS_AIX_VM_PORTING_AIX_HPP + #include +// PPC port only: +#define assert0(b) assert( (b), "" ) +#define guarantee0(b) assert( (b), "" ) +template bool is_aligned_to(T1 what, T2 alignment) { + return ( ((uintx)(what)) & (((uintx)(alignment)) - 1) ) == 0 ? true : false; +} + // Header file to contain porting-relevant code which does not have a // home anywhere else and which can not go into os_.h because // that header is included inside the os class definition, hence all @@ -79,3 +89,62 @@ const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages ); + +// ------------------------------------------------------------------------- + +// A simple critical section which shall be based upon OS critical +// sections (CRITICAL_SECTION resp. Posix Mutex) and nothing else. + +#include + +namespace MiscUtils { + typedef pthread_mutex_t critsect_t; + + inline void init_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_init(cs, NULL); + } + inline void free_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_destroy(cs); + } + inline void enter_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_lock(cs); + } + inline void leave_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_unlock(cs); + } + + // Need to wrap this in an object because we need to dynamically initialize + // critical section (because of windows, where there is no way to initialize + // a CRITICAL_SECTION statically. On Unix, we could use + // PTHREAD_MUTEX_INITIALIZER) + + // Note: The critical section does NOT get cleaned up in the destructor. That is + // by design: the CritSect class is only ever used as global objects whose + // lifetime spans the whole VM life; in that context we don't want the lock to + // be cleaned up when global C++ objects are destroyed, but to continue to work + // correctly right to the very end of the process life. + class CritSect { + critsect_t _cs; + public: + CritSect() { init_critsect(&_cs); } + //~CritSect() { free_critsect(&_cs); } + void enter() { enter_critsect(&_cs); } + void leave() { leave_critsect(&_cs); } + }; + + class AutoCritSect { + CritSect* const _pcsobj; + public: + AutoCritSect(CritSect* pcsobj) + : _pcsobj(pcsobj) + { + _pcsobj->enter(); + } + ~AutoCritSect() { + _pcsobj->leave(); + } + }; + +} + +#endif // OS_AIX_VM_PORTING_AIX_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -129,7 +129,7 @@ bool is_inconsistent() { return _state == INCONSISTENT; } void set_inconsistent() { _state = INCONSISTENT; } - void visit(picl_nodehdl_t nodeh, const char* name) { + bool visit(picl_nodehdl_t nodeh, const char* name) { assert(!is_inconsistent(), "Precondition"); int curr; if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { @@ -138,7 +138,9 @@ } else if (curr != value()) { // following iterations set_inconsistent(); } + return true; } + return false; } }; @@ -155,8 +157,19 @@ if (!l1_visitor->is_inconsistent()) { l1_visitor->visit(nodeh, "l1-dcache-line-size"); } - if (!l2_visitor->is_inconsistent()) { - l2_visitor->visit(nodeh, "l2-cache-line-size"); + static const char* l2_data_cache_line_property_name = NULL; + // On the first visit determine the name of the l2 cache line size property and memoize it. + if (l2_data_cache_line_property_name == NULL) { + assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent"); + l2_data_cache_line_property_name = "l2-cache-line-size"; + if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) { + l2_data_cache_line_property_name = "l2-dcache-line-size"; + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); + } + } else { + if (!l2_visitor->is_inconsistent()) { + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); + } } if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) { @@ -172,13 +185,13 @@ UniqueValueVisitor* l2_visitor() { return &_l2_visitor; } }; int _L1_data_cache_line_size; - int _L2_cache_line_size; + int _L2_data_cache_line_size; public: static int visit_cpu(picl_nodehdl_t nodeh, void *state) { return CPUVisitor::visit(nodeh, state); } - PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) { + PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) { if (!open_library()) { return; } @@ -196,7 +209,7 @@ _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value(); } if (cpu_visitor.l2_visitor()->is_assigned()) { - _L2_cache_line_size = cpu_visitor.l2_visitor()->value(); + _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value(); } } _picl_shutdown(); @@ -205,7 +218,7 @@ } unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } - unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } + unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; } }; @@ -431,7 +444,7 @@ // Figure out cache line sizes using PICL PICL picl((features & sparc64_family_m) != 0); _L1_data_cache_line_size = picl.L1_data_cache_line_size(); - _L2_cache_line_size = picl.L2_cache_line_size(); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); return features; } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/adlparse.cpp --- a/hotspot/src/share/vm/adlc/adlparse.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/adlparse.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -800,6 +800,7 @@ } if (strcmp(token,"reg_def")==0) { reg_def_parse(); } else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); } else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } else if (strcmp(token,"#define")==0) { preproc_define(); } else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } @@ -2323,11 +2324,12 @@ // Debug Stuff if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname); - RegClass *reg_class = _AD._register->addRegClass(cname); - - // Collect registers in class skipws(); if (_curchar == '(') { + // A register list is defined for the register class. + // Collect registers into a generic RegClass register class. + RegClass* reg_class = _AD._register->addRegClass(cname); + next_char(); // Skip '(' skipws(); while (_curchar != ')') { @@ -2352,12 +2354,15 @@ } next_char(); // Skip closing ')' } else if (_curchar == '%') { + // A code snippet is defined for the register class. + // Collect the code snippet into a CodeSnippetRegClass register class. + CodeSnippetRegClass* reg_class = _AD._register->addRegClass(cname); char *code = find_cpp_block("reg class"); if (code == NULL) { parse_err(SYNERR, "missing code declaration for reg class.\n"); return; } - reg_class->_user_defined = code; + reg_class->set_code_snippet(code); return; } @@ -2374,6 +2379,87 @@ return; } +//------------------------------reg_class_dynamic_parse------------------------ +void ADLParser::reg_class_dynamic_parse(void) { + char *cname; // Name of dynamic register class being defined + + // Get register class name + skipws(); + cname = get_ident(); + if (cname == NULL) { + parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n"); + return; + } + + if (_AD._adl_debug > 1) { + fprintf(stdout, "Dynamic Register Class: %s\n", cname); + } + + skipws(); + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n"); + return; + } + next_char(); + skipws(); + + // Collect two register classes and the C++ code representing the condition code used to + // select between the two classes into a ConditionalRegClass register class. + ConditionalRegClass* reg_class = _AD._register->addRegClass(cname); + int i; + for (i = 0; i < 2; i++) { + char* name = get_ident(); + if (name == NULL) { + parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n"); + return; + } + RegClass* rc = _AD._register->getRegClass(name); + if (rc == NULL) { + parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name); + } else { + reg_class->set_rclass_at_index(i, rc); + } + + skipws(); + if (_curchar == ',') { + next_char(); + skipws(); + } else { + parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n"); + } + } + + // Collect the condition code. + skipws(); + if (_curchar == '%') { + char* code = find_cpp_block("reg class dynamic"); + if (code == NULL) { + parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n"); + return; + } + reg_class->set_condition_code(code); + } else { + parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n"); + return; + } + + skipws(); + if (_curchar != ')') { + parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n"); + return; + } + next_char(); + + skipws(); + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n"); + return; + } + next_char(); // Skip trailing ';' + + return; +} + //------------------------------alloc_class_parse------------------------------ void ADLParser::alloc_class_parse(void) { char *name; // Name of allocation class being defined diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/adlparse.hpp --- a/hotspot/src/share/vm/adlc/adlparse.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/adlparse.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -53,6 +53,8 @@ // ***** Register Section ***** class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; // ***** Pipeline Section ***** @@ -125,6 +127,7 @@ // Parse components of the register section void reg_def_parse(void); // Parse register definition void reg_class_parse(void); // Parse register class definition + void reg_class_dynamic_parse(void); // Parse dynamic register class definition void alloc_class_parse(void); // Parse allocation class definition // Parse components of the definition section diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/archDesc.cpp --- a/hotspot/src/share/vm/adlc/archDesc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/archDesc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -908,7 +908,7 @@ void ArchDesc::set_stack_or_reg(const char *reg_class_name) { if( _register ) { RegClass *reg_class = _register->getRegClass(reg_class_name); - reg_class->_stack_or_reg = true; + reg_class->set_stack_version(true); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/forms.hpp --- a/hotspot/src/share/vm/adlc/forms.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/forms.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -68,6 +68,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/formsopt.cpp --- a/hotspot/src/share/vm/adlc/formsopt.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/formsopt.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -47,13 +47,19 @@ } // record a new register class -RegClass *RegisterForm::addRegClass(const char *className) { - RegClass *regClass = new RegClass(className); +template +T* RegisterForm::addRegClass(const char* className) { + T* regClass = new T(className); _rclasses.addName(className); - _regClass.Insert(className,regClass); + _regClass.Insert(className, regClass); return regClass; } +// Explicit instantiation for all supported register classes. +template RegClass* RegisterForm::addRegClass(const char* className); +template CodeSnippetRegClass* RegisterForm::addRegClass(const char* className); +template ConditionalRegClass* RegisterForm::addRegClass(const char* className); + // record a new register class AllocClass *RegisterForm::addAllocClass(char *className) { AllocClass *allocClass = new AllocClass(className); @@ -67,9 +73,9 @@ void RegisterForm::addSpillRegClass() { // Stack slots start at the next available even register number. _reg_ctr = (_reg_ctr+7) & ~7; - const char *rc_name = "stack_slots"; - RegClass *reg_class = new RegClass(rc_name); - reg_class->_stack_or_reg = true; + const char *rc_name = "stack_slots"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(true); _rclasses.addName(rc_name); _regClass.Insert(rc_name,reg_class); } @@ -224,9 +230,11 @@ //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted -RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena), - _user_defined(NULL) -{ +RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr, hashstr, Form::arena) { +} + +RegClass::~RegClass() { + delete _classid; } // record a register in this class @@ -305,6 +313,91 @@ fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } +void RegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + if (_stack_or_reg) { + fprintf(fp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + } + delete[] rc_name_to_upper; +} + +void RegClass::build_register_masks(FILE* fp) { + int len = RegisterForm::RegMask_Size(); + const char *prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); + + int i; + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, false)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, false)); + + if (_stack_or_reg) { + fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, true)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, true)); + } + delete[] rc_name_to_upper; +} + +//------------------------------CodeSnippetRegClass--------------------------- +CodeSnippetRegClass::CodeSnippetRegClass(const char* classid) : RegClass(classid), _code_snippet(NULL) { +} + +CodeSnippetRegClass::~CodeSnippetRegClass() { + delete _code_snippet; +} + +void CodeSnippetRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, _code_snippet); + delete[] rc_name_to_upper; +} + +//------------------------------ConditionalRegClass--------------------------- +ConditionalRegClass::ConditionalRegClass(const char *classid) : RegClass(classid), _condition_code(NULL) { +} + +ConditionalRegClass::~ConditionalRegClass() { + delete _condition_code; +} + +void ConditionalRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + const char* rclass_0_to_upper = toUpper(_rclasses[0]->_classid); + const char* rclass_1_to_upper = toUpper(_rclasses[1]->_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() {" + " return (%s) ?" + " %s%s_mask() :" + " %s%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + if (_stack_or_reg) { + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() {" + " return (%s) ?" + " %sSTACK_OR_%s_mask() :" + " %sSTACK_OR_%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + } + delete[] rc_name_to_upper; + delete[] rclass_0_to_upper; + delete[] rclass_1_to_upper; + return; +} //------------------------------AllocClass------------------------------------- AllocClass::AllocClass(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/formsopt.hpp --- a/hotspot/src/share/vm/adlc/formsopt.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/formsopt.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -60,6 +60,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; @@ -98,7 +100,8 @@ void addRegDef(char *regName, char *callingConv, char *c_conv, char * idealtype, char *encoding, char* concreteName); - RegClass *addRegClass(const char *className); + template T* addRegClass(const char* className); + AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); @@ -154,17 +157,28 @@ }; //------------------------------RegClass--------------------------------------- +// Generic register class. This register class is the internal representation +// for the following .ad file format: +// +// reg_class ptr(RAX, RBX, ...); +// +// where ptr is the name of the register class, RAX and RBX are registers. +// +// This register class allows registers to be spilled onto the stack. Spilling +// is allowed is field _stack_or_reg is true. class RegClass : public Form { public: // Public Data const char *_classid; // Name of class NameList _regDefs; // List of registers in class Dict _regDef; // Dictionary of registers in class +protected: bool _stack_or_reg; // Allowed on any stack slot - char* _user_defined; +public: // Public Methods RegClass(const char *classid);// Constructor + virtual ~RegClass(); void addReg(RegDef *regDef); // Add a register to this class @@ -183,6 +197,115 @@ void dump(); // Debug printer void output(FILE *fp); // Write info to output files + + virtual bool has_stack_version() { + return _stack_or_reg; + } + virtual void set_stack_version(bool flag) { + _stack_or_reg = flag; + } + + virtual void declare_register_masks(FILE* fp); + virtual void build_register_masks(FILE* fp); +}; + +//------------------------------CodeSnippetRegClass---------------------------- +// Register class that has an user-defined C++ code snippet attached to it +// to determine at runtime which register class to use. This register class is +// the internal representation for the following .ad file format: +// +// reg_class actual_dflt_reg %{ +// if (VM_Version::has_vfp3_32()) { +// return DFLT_REG_mask(); +// } else { +// return DFLT_LOW_REG_mask(); +// } +// %} +// +// where DFLT_REG_mask() and DFLT_LOW_REG_mask() are the internal names of the +// masks of register classes dflt_reg and dflt_low_reg. +// +// The attached code snippet can select also between more than two register classes. +// This register class can be, however, used only if the register class is not +// cisc-spillable (i.e., the registers of this class are not allowed on the stack, +// which is equivalent with _stack_or_reg being false). +class CodeSnippetRegClass : public RegClass { +protected: + char* _code_snippet; +public: + CodeSnippetRegClass(const char* classid);// Constructor + ~CodeSnippetRegClass(); + + void set_code_snippet(char* code) { + _code_snippet = code; + } + char* code_snippet() { + return _code_snippet; + } + void set_stack_version(bool flag) { + assert(false, "User defined register classes are not allowed to spill to the stack."); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } +}; + +//------------------------------ConditionalRegClass---------------------------- +// Register class that has two register classes and a runtime condition attached +// to it. The condition is evaluated at runtime and either one of the register +// attached register classes is selected. This register class is the internal +// representation for the following .ad format: +// +// reg_class_dynamic actual_dflt_reg(dflt_reg, low_reg, +// %{ VM_Version::has_vfp3_32() }% +// ); +// +// This example is equivalent to the example used with the CodeSnippetRegClass +// register class. A ConditionalRegClass works also if a register class is cisc-spillable +// (i.e., _stack_or_reg is true), but if can select only between two register classes. +class ConditionalRegClass : public RegClass { +protected: + // reference to condition code + char* _condition_code; // C++ condition code to dynamically determine which register class to use. + + // Example syntax (equivalent to previous example): + // + // reg_class actual_dflt_reg(dflt_reg, low_reg, + // %{ VM_Version::has_vfp3_32() }% + // ); + // reference to conditional register classes + RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true + // 1 is the register class selected if the condition code returns false +public: + ConditionalRegClass(const char* classid);// Constructor + ~ConditionalRegClass(); + + virtual void set_stack_version(bool flag) { + RegClass::set_stack_version(flag); + assert((_rclasses[0] != NULL), "Register class NULL for condition code == true"); + assert((_rclasses[1] != NULL), "Register class NULL for condition code == false"); + _rclasses[0]->set_stack_version(flag); + _rclasses[1]->set_stack_version(flag); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } + void set_rclass_at_index(int index, RegClass* rclass) { + assert((0 <= index && index < 2), "Condition code can select only between two register classes"); + _rclasses[index] = rclass; + } + void set_condition_code(char* code) { + _condition_code = code; + } + char* condition_code() { + return _condition_code; + } }; //------------------------------AllocClass------------------------------------- diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/formssel.cpp --- a/hotspot/src/share/vm/adlc/formssel.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/formssel.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -4043,6 +4043,13 @@ strcmp(opType,"ReplicateL")==0 || strcmp(opType,"ReplicateF")==0 || strcmp(opType,"ReplicateD")==0 || + strcmp(opType,"AddReductionVI")==0 || + strcmp(opType,"AddReductionVL")==0 || + strcmp(opType,"AddReductionVF")==0 || + strcmp(opType,"AddReductionVD")==0 || + strcmp(opType,"MulReductionVI")==0 || + strcmp(opType,"MulReductionVF")==0 || + strcmp(opType,"MulReductionVD")==0 || 0 /* 0 to line up columns nicely */ ) return 1; } @@ -4135,6 +4142,10 @@ "MulVS","MulVI","MulVF","MulVD", "DivVF","DivVD", "AndV" ,"XorV" ,"OrV", + "AddReductionVI", "AddReductionVL", + "AddReductionVF", "AddReductionVD", + "MulReductionVI", + "MulReductionVF", "MulReductionVD", "LShiftCntV","RShiftCntV", "LShiftVB","LShiftVS","LShiftVI","LShiftVL", "RShiftVB","RShiftVS","RShiftVI","RShiftVL", diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/formssel.hpp --- a/hotspot/src/share/vm/adlc/formssel.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/formssel.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -59,6 +59,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeDesc; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/adlc/output_c.cpp --- a/hotspot/src/share/vm/adlc/output_c.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/adlc/output_c.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -138,26 +138,9 @@ fprintf(fp_hpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - const char* rc_name_to_upper = toUpper(rc_name); - - if (reg_class->_user_defined == NULL) { - fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } else { - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, reg_class->_user_defined); - } - - if (reg_class->_stack_or_reg) { - assert(reg_class->_user_defined == NULL, "no user defined reg class here"); - fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } - delete[] rc_name_to_upper; - + reg_class->declare_register_masks(fp_hpp); } } } @@ -173,35 +156,9 @@ fprintf(fp_cpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - if (reg_class->_user_defined != NULL) { - continue; - } - - int len = RegisterForm::RegMask_Size(); - const char* rc_name_to_upper = toUpper(rc_name); - fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); - - { - int i; - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,", reg_class->regs_in_word(i, false)); - } - fprintf(fp_cpp," 0x%x );\n", reg_class->regs_in_word(i, false)); - } - - if (reg_class->_stack_or_reg) { - int i; - fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i, true)); - } - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i, true)); - } - delete[] rc_name_to_upper; + reg_class->build_register_masks(fp_cpp); } } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -3462,6 +3462,24 @@ case vmIntrinsics::_putFloat : return append_unsafe_put_obj(callee, T_FLOAT, false); case vmIntrinsics::_putDouble : return append_unsafe_put_obj(callee, T_DOUBLE, false); + case vmIntrinsics::_getShortUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_SHORT, false) : false; + case vmIntrinsics::_getCharUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_CHAR, false) : false; + case vmIntrinsics::_getIntUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_INT, false) : false; + case vmIntrinsics::_getLongUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_LONG, false) : false; + + case vmIntrinsics::_putShortUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_SHORT, false) : false; + case vmIntrinsics::_putCharUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_CHAR, false) : false; + case vmIntrinsics::_putIntUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_INT, false) : false; + case vmIntrinsics::_putLongUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_LONG, false) : false; + case vmIntrinsics::_getObjectVolatile : return append_unsafe_get_obj(callee, T_OBJECT, true); case vmIntrinsics::_getBooleanVolatile: return append_unsafe_get_obj(callee, T_BOOLEAN, true); case vmIntrinsics::_getByteVolatile : return append_unsafe_get_obj(callee, T_BYTE, true); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -688,7 +688,8 @@ // via assert_unique_concrete_method or assert_leaf_type. ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_recv) { + ciInstanceKlass* actual_recv, + bool check_access) { check_is_loaded(); if (actual_recv->is_interface()) { @@ -696,7 +697,7 @@ return NULL; } - ciMethod* root_m = resolve_invoke(caller, actual_recv); + ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access); if (root_m == NULL) { // Something went wrong looking up the actual receiver method. return NULL; @@ -775,7 +776,7 @@ // // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or the target is abstract. -ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) { +ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access) { check_is_loaded(); VM_ENTRY_MARK; @@ -792,9 +793,9 @@ || InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) { if (holder()->is_interface()) { - m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } else { - m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -255,11 +255,12 @@ // its calling environment. ciMethod* find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_receiver); + ciInstanceKlass* actual_receiver, + bool check_access = true); // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or is abstract. - ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver); + ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access = true); // Find the proper vtable index to invoke this method. int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -868,9 +868,12 @@ \ /* Custom branch frequencies profiling support for JSR292 */ \ do_class(java_lang_invoke_MethodHandleImpl, "java/lang/invoke/MethodHandleImpl") \ - do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ - do_name( profileBoolean_name, "profileBoolean") \ - do_signature(profileBoolean_signature, "(Z[I)Z") \ + do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ + do_name( profileBoolean_name, "profileBoolean") \ + do_signature(profileBoolean_signature, "(Z[I)Z") \ + do_intrinsic(_isCompileConstant, java_lang_invoke_MethodHandleImpl, isCompileConstant_name, isCompileConstant_signature, F_S) \ + do_name( isCompileConstant_name, "isCompileConstant") \ + do_alias( isCompileConstant_signature, object_boolean_signature) \ \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ @@ -950,6 +953,20 @@ do_intrinsic(_putFloatVolatile, sun_misc_Unsafe, putFloatVolatile_name, putFloat_signature, F_RN) \ do_intrinsic(_putDoubleVolatile, sun_misc_Unsafe, putDoubleVolatile_name, putDouble_signature, F_RN) \ \ + do_name(getShortUnaligned_name,"getShortUnaligned") do_name(putShortUnaligned_name,"putShortUnaligned") \ + do_name(getCharUnaligned_name,"getCharUnaligned") do_name(putCharUnaligned_name,"putCharUnaligned") \ + do_name(getIntUnaligned_name,"getIntUnaligned") do_name(putIntUnaligned_name,"putIntUnaligned") \ + do_name(getLongUnaligned_name,"getLongUnaligned") do_name(putLongUnaligned_name,"putLongUnaligned") \ + \ + do_intrinsic(_getShortUnaligned, sun_misc_Unsafe, getShortUnaligned_name, getShort_signature, F_R) \ + do_intrinsic(_getCharUnaligned, sun_misc_Unsafe, getCharUnaligned_name, getChar_signature, F_R) \ + do_intrinsic(_getIntUnaligned, sun_misc_Unsafe, getIntUnaligned_name, getInt_signature, F_R) \ + do_intrinsic(_getLongUnaligned, sun_misc_Unsafe, getLongUnaligned_name, getLong_signature, F_R) \ + do_intrinsic(_putShortUnaligned, sun_misc_Unsafe, putShortUnaligned_name, putShort_signature, F_R) \ + do_intrinsic(_putCharUnaligned, sun_misc_Unsafe, putCharUnaligned_name, putChar_signature, F_R) \ + do_intrinsic(_putIntUnaligned, sun_misc_Unsafe, putIntUnaligned_name, putInt_signature, F_R) \ + do_intrinsic(_putLongUnaligned, sun_misc_Unsafe, putLongUnaligned_name, putLong_signature, F_R) \ + \ /* %%% these are redundant except perhaps for getAddress, but Unsafe has native methods for them */ \ do_signature(getByte_raw_signature, "(J)B") \ do_signature(putByte_raw_signature, "(JB)V") \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/code/dependencies.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -845,7 +845,13 @@ assert((uint)n <= (uint)_num_participants, "oob"); Method* fm = _found_methods[n]; assert(n == _num_participants || fm != NULL, "proper usage"); - assert(fm == NULL || fm->method_holder() == _participants[n], "sanity"); + if (fm != NULL && fm->method_holder() != _participants[n]) { + // Default methods from interfaces can be added to classes. In + // that case the holder of the method is not the class but the + // interface where it's defined. + assert(fm->is_default_method(), "sanity"); + return NULL; + } return fm; } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/code/nmethod.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -504,7 +504,7 @@ basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); - if (PrintAssembly && nm != NULL) { + if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { Disassembler::decode(nm); } } @@ -2837,11 +2837,21 @@ st.print(")"); return st.as_string(); } + case relocInfo::runtime_call_type: { + stringStream st; + st.print("runtime_call"); + runtime_call_Relocation* r = iter.runtime_call_reloc(); + address dest = r->destination(); + CodeBlob* cb = CodeCache::find_blob(dest); + if (cb != NULL) { + st.print(" %s", cb->name()); + } + return st.as_string(); + } case relocInfo::virtual_call_type: return "virtual_call"; case relocInfo::opt_virtual_call_type: return "optimized virtual_call"; case relocInfo::static_call_type: return "static_call"; case relocInfo::static_stub_type: return "static_stub"; - case relocInfo::runtime_call_type: return "runtime_call"; case relocInfo::external_word_type: return "external_word"; case relocInfo::internal_word_type: return "internal_word"; case relocInfo::section_word_type: return "section_word"; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/code/pcDesc.cpp --- a/hotspot/src/share/vm/code/pcDesc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/code/pcDesc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -54,12 +54,7 @@ for (ScopeDesc* sd = code->scope_desc_at(real_pc(code)); sd != NULL; sd = sd->sender()) { - tty->print(" "); - sd->method()->print_short_name(tty); - tty->print(" @%d", sd->bci()); - if (sd->should_reexecute()) - tty->print(" reexecute=true"); - tty->cr(); + sd->print_on(tty); } #endif } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -157,14 +157,18 @@ #ifndef PRODUCT void ScopeDesc::print_value_on(outputStream* st) const { - tty->print(" "); + st->print(" "); method()->print_short_name(st); int lineno = method()->line_number_from_bci(bci()); if (lineno != -1) { - st->print_cr("@%d (line %d)", bci(), lineno); + st->print("@%d (line %d)", bci(), lineno); } else { - st->print_cr("@%d", bci()); + st->print("@%d", bci()); } + if (should_reexecute()) { + st->print(" reexecute=true"); + } + st->cr(); } void ScopeDesc::print_on(outputStream* st) const { @@ -174,7 +178,7 @@ void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { // header if (pd != NULL) { - tty->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); + st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); } print_value_on(st); @@ -192,7 +196,7 @@ // locals { GrowableArray* l = ((ScopeDesc*) this)->locals(); if (l != NULL) { - tty->print_cr(" Locals"); + st->print_cr(" Locals"); for (int index = 0; index < l->length(); index++) { st->print(" - l%d: ", index); l->at(index)->print_on(st); @@ -205,7 +209,7 @@ if (l != NULL) { st->print_cr(" Expression stack"); for (int index = 0; index < l->length(); index++) { - st->print(" - @%d: ", index); + st->print(" - @%d: ", index); l->at(index)->print_on(st); st->cr(); } @@ -225,12 +229,12 @@ #ifdef COMPILER2 if (DoEscapeAnalysis && is_top() && _objects != NULL) { - tty->print_cr("Objects"); + st->print_cr(" Objects"); for (int i = 0; i < _objects->length(); i++) { ObjectValue* sv = (ObjectValue*) _objects->at(i); - tty->print(" - %d: ", sv->id()); - sv->print_fields_on(tty); - tty->cr(); + st->print(" - %d: ", sv->id()); + sv->print_fields_on(st); + st->cr(); } } #endif // COMPILER2 diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/freeBlockDictionary.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.inline.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" + +// Generate CMS specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -32,6 +32,7 @@ #include "gc_interface/collectedHeap.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/resourceArea.hpp" #include "memory/space.inline.hpp" #include "memory/universe.inline.hpp" @@ -673,10 +674,10 @@ HeapWord* bottom, \ HeapWord* top, \ ClosureType* cl) { \ - bool is_par = SharedHeap::heap()->n_par_threads() > 0; \ + bool is_par = GenCollectedHeap::heap()->n_par_threads() > 0; \ if (is_par) { \ - assert(SharedHeap::heap()->n_par_threads() == \ - SharedHeap::heap()->workers()->active_workers(), "Mismatch"); \ + assert(GenCollectedHeap::heap()->n_par_threads() == \ + GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch"); \ walk_mem_region_with_cl_par(mr, bottom, top, cl); \ } else { \ walk_mem_region_with_cl_nopar(mr, bottom, top, cl); \ @@ -1907,11 +1908,11 @@ assert(chunk->is_free() && ffc->is_free(), "Error"); _bt.split_block((HeapWord*)chunk, chunk->size(), new_size); if (rem_sz < SmallForDictionary) { - bool is_par = (SharedHeap::heap()->n_par_threads() > 0); + bool is_par = (GenCollectedHeap::heap()->n_par_threads() > 0); if (is_par) _indexedFreeListParLocks[rem_sz]->lock(); assert(!is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); + (GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch"); returnChunkToFreeList(ffc); split(size, rem_sz); if (is_par) _indexedFreeListParLocks[rem_sz]->unlock(); @@ -1982,7 +1983,7 @@ bool CompactibleFreeListSpace::no_allocs_since_save_marks() { assert(_promoInfo.tracking(), "No preceding save_marks?"); - assert(SharedHeap::heap()->n_par_threads() == 0, + assert(GenCollectedHeap::heap()->n_par_threads() == 0, "Shouldn't be called if using parallel gc."); return _promoInfo.noPromotions(); } @@ -1991,7 +1992,7 @@ \ void CompactibleFreeListSpace:: \ oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) { \ - assert(SharedHeap::heap()->n_par_threads() == 0, \ + assert(GenCollectedHeap::heap()->n_par_threads() == 0, \ "Shouldn't be called (yet) during parallel part of gc."); \ _promoInfo.promoted_oops_iterate##nv_suffix(blk); \ /* \ @@ -2442,11 +2443,10 @@ { VerifyAllOopsClosure cl(_collector, this, span, past_remark, _collector->markBitMap()); - CollectedHeap* ch = Universe::heap(); // Iterate over all oops in the heap. Uses the _no_header version // since we are not interested in following the klass pointers. - ch->oop_iterate_no_header(&cl); + GenCollectedHeap::heap()->oop_iterate_no_header(&cl); } if (VerifyObjectStartArray) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -28,7 +28,7 @@ #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" #include "memory/binaryTreeDictionary.hpp" -#include "memory/blockOffsetTable.inline.hpp" +#include "memory/blockOffsetTable.hpp" #include "memory/freeList.hpp" #include "memory/space.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -53,6 +53,7 @@ #include "memory/padded.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/tenuredGeneration.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -64,6 +65,7 @@ #include "runtime/vmThread.hpp" #include "services/memoryService.hpp" #include "services/runtimeService.hpp" +#include "utilities/stack.inline.hpp" // statics CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL; @@ -208,10 +210,6 @@ use_adaptive_freelists, dictionaryChoice); NOT_PRODUCT(debug_cms_space = _cmsSpace;) - if (_cmsSpace == NULL) { - vm_exit_during_initialization( - "CompactibleFreeListSpace allocation failure"); - } _cmsSpace->_gen = this; _gc_stats = new CMSGCStats(); @@ -230,14 +228,8 @@ typedef CMSParGCThreadState* CMSParGCThreadStatePtr; _par_gc_thread_states = NEW_C_HEAP_ARRAY(CMSParGCThreadStatePtr, ParallelGCThreads, mtGC); - if (_par_gc_thread_states == NULL) { - vm_exit_during_initialization("Could not allocate par gc structs"); - } for (uint i = 0; i < ParallelGCThreads; i++) { _par_gc_thread_states[i] = new CMSParGCThreadState(cmsSpace()); - if (_par_gc_thread_states[i] == NULL) { - vm_exit_during_initialization("Could not allocate par gc structs"); - } } } else { _par_gc_thread_states = NULL; @@ -308,8 +300,6 @@ AdaptiveSizePolicy* CMSCollector::size_policy() { GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "Wrong type of heap"); return gch->gen_policy()->size_policy(); } @@ -586,11 +576,6 @@ return; } _hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC); - if (_hash_seed == NULL) { - warning("_hash_seed array allocation failure"); - return; - } - typedef Padded PaddedOopTaskQueue; for (i = 0; i < num_queues; i++) { PaddedOopTaskQueue *q = new PaddedOopTaskQueue(); @@ -633,12 +618,7 @@ _eden_chunk_index = 0; _eden_chunk_capacity = (_young_gen->max_capacity()+CMSSamplingGrain)/CMSSamplingGrain; _eden_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, _eden_chunk_capacity, mtGC); - if (_eden_chunk_array == NULL) { - _eden_chunk_capacity = 0; - warning("GC/CMS: _eden_chunk_array allocation failure"); - } - } - assert(_eden_chunk_array != NULL || _eden_chunk_capacity == 0, "Error"); + } // Support for parallelizing survivor space rescan if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) { @@ -648,52 +628,15 @@ _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC); _cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads, mtGC); - if (_survivor_plab_array == NULL || _survivor_chunk_array == NULL - || _cursor == NULL) { - warning("Failed to allocate survivor plab/chunk array"); - if (_survivor_plab_array != NULL) { - FREE_C_HEAP_ARRAY(ChunkArray, _survivor_plab_array); - _survivor_plab_array = NULL; - } - if (_survivor_chunk_array != NULL) { - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_chunk_array); - _survivor_chunk_array = NULL; - } - if (_cursor != NULL) { - FREE_C_HEAP_ARRAY(size_t, _cursor); - _cursor = NULL; - } - } else { - _survivor_chunk_capacity = 2*max_plab_samples; - for (uint i = 0; i < ParallelGCThreads; i++) { - HeapWord** vec = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC); - if (vec == NULL) { - warning("Failed to allocate survivor plab array"); - for (int j = i; j > 0; j--) { - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_plab_array[j-1].array()); - } - FREE_C_HEAP_ARRAY(ChunkArray, _survivor_plab_array); - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_chunk_array); - _survivor_plab_array = NULL; - _survivor_chunk_array = NULL; - _survivor_chunk_capacity = 0; - break; - } else { - ChunkArray* cur = - ::new (&_survivor_plab_array[i]) ChunkArray(vec, - max_plab_samples); - assert(cur->end() == 0, "Should be 0"); - assert(cur->array() == vec, "Should be vec"); - assert(cur->capacity() == max_plab_samples, "Error"); - } - } - } - } - assert( ( _survivor_plab_array != NULL - && _survivor_chunk_array != NULL) - || ( _survivor_chunk_capacity == 0 - && _survivor_chunk_index == 0), - "Error"); + _survivor_chunk_capacity = 2*max_plab_samples; + for (uint i = 0; i < ParallelGCThreads; i++) { + HeapWord** vec = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC); + ChunkArray* cur = ::new (&_survivor_plab_array[i]) ChunkArray(vec, max_plab_samples); + assert(cur->end() == 0, "Should be 0"); + assert(cur->array() == vec, "Should be vec"); + assert(cur->capacity() == max_plab_samples, "Error"); + } + } NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;) _gc_counters = new CollectorCounters("CMS", 1); @@ -1037,7 +980,7 @@ assert_lock_strong(freelistLock()); #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -1114,7 +1057,7 @@ oop old, markOop m, size_t word_sz) { #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -2524,7 +2467,7 @@ verification_mark_bm()->iterate(&vcl); if (vcl.failed()) { gclog_or_tty->print("Verification failed"); - Universe::heap()->print_on(gclog_or_tty); + gch->print_on(gclog_or_tty); fatal("CMS: failed marking verification after remark"); } } @@ -3071,10 +3014,10 @@ gch->set_par_threads(n_workers); initialize_sequential_subtasks_for_young_gen_rescan(n_workers); if (n_workers > 1) { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } gch->set_par_threads(0); @@ -5169,11 +5112,11 @@ // necessarily be so, since it's possible that we are doing // ST marking. ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), true); - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), false); - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } @@ -5241,7 +5184,7 @@ verify_work_stacks_empty(); gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; gch->gen_process_roots(_cmsGen->level(), true, // younger gens as roots diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -38,8 +38,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/virtualspace.hpp" #include "services/memoryService.hpp" -#include "utilities/bitMap.inline.hpp" -#include "utilities/stack.inline.hpp" +#include "utilities/bitMap.hpp" +#include "utilities/stack.hpp" #include "utilities/taskqueue.hpp" #include "utilities/yieldingWorkgroup.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -27,7 +27,7 @@ #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/shared/concurrentGCThread.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/thread.hpp" class ConcurrentMarkSweepGeneration; class CMSCollector; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/genOopClosures.hpp" #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" #include "oops/markOop.inline.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); - Universe::heap()->prepare_for_verify(); + GenCollectedHeap::heap()->prepare_for_verify(); Universe::verify(); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -34,6 +34,7 @@ #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionManager.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" @@ -46,6 +47,7 @@ #include "memory/genOopClosures.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" +#include "memory/strongRootsScope.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -115,7 +117,7 @@ } size_t CMBitMap::compute_size(size_t heap_size) { - return heap_size / mark_distance(); + return ReservedSpace::allocation_align_size_up(heap_size / mark_distance()); } size_t CMBitMap::mark_distance() { @@ -1325,7 +1327,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(before)"); } @@ -1352,7 +1354,7 @@ // Verify the heap w.r.t. the previous marking bitmap. if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(overflow)"); } @@ -1378,7 +1380,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UseNextMarking, " VerifyDuringGC:(after)"); } @@ -1986,13 +1988,13 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(before)"); } g1h->check_bitmaps("Cleanup Start"); - G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + G1CollectorPolicy* g1p = g1h->g1_policy(); g1p->record_concurrent_mark_cleanup_start(); double start = os::elapsedTime(); @@ -2097,7 +2099,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(after)"); } @@ -2650,7 +2652,7 @@ g1h->ensure_parsability(false); - G1CollectedHeap::StrongRootsScope srs(g1h); + StrongRootsScope srs; // this is remark, so we'll use up all active threads uint active_workers = g1h->workers()->active_workers(); if (active_workers == 0) { @@ -3392,22 +3394,29 @@ } #endif -void CMTask::scan_object(oop obj) { +template +inline void CMTask::process_grey_object(oop obj) { + assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT, + gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } size_t obj_size = obj->size(); _words_scanned += obj_size; - obj->oop_iterate(_cm_oop_closure); + if (scan) { + obj->oop_iterate(_cm_oop_closure); + } statsOnly( ++_objs_scanned ); check_limits(); } +template void CMTask::process_grey_object(oop); +template void CMTask::process_grey_object(oop); + // Closure for iteration over bitmaps class CMBitMapClosure : public BitMapClosure { private: diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1100,6 +1100,12 @@ void regular_clock_call(); bool concurrent() { return _concurrent; } + // Test whether objAddr might have already been passed over by the + // mark bitmap scan, and so needs to be pushed onto the mark stack. + bool is_below_finger(HeapWord* objAddr, HeapWord* global_finger) const; + + template void process_grey_object(oop obj); + public: // It resets the task; it should be called right at the beginning of // a marking phase. @@ -1152,7 +1158,7 @@ inline void deal_with_reference(oop obj); // It scans an object and visits its children. - void scan_object(oop obj); + void scan_object(oop obj) { process_grey_object(obj); } // It pushes an object on the local queue. inline void push(oop obj); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -259,14 +259,35 @@ ++_local_pushes ); } -// This determines whether the method below will check both the local -// and global fingers when determining whether to push on the stack a -// gray object (value 1) or whether it will only check the global one -// (value 0). The tradeoffs are that the former will be a bit more -// accurate and possibly push less on the stack, but it might also be -// a little bit slower. +inline bool CMTask::is_below_finger(HeapWord* objAddr, + HeapWord* global_finger) const { + // If objAddr is above the global finger, then the mark bitmap scan + // will find it later, and no push is needed. Similarly, if we have + // a current region and objAddr is between the local finger and the + // end of the current region, then no push is needed. The tradeoff + // of checking both vs only checking the global finger is that the + // local check will be more accurate and so result in fewer pushes, + // but may also be a little slower. + if (_finger != NULL) { + // We have a current region. -#define _CHECK_BOTH_FINGERS_ 1 + // Finger and region values are all NULL or all non-NULL. We + // use _finger to check since we immediately use its value. + assert(_curr_region != NULL, "invariant"); + assert(_region_limit != NULL, "invariant"); + assert(_region_limit <= global_finger, "invariant"); + + // True if objAddr is less than the local finger, or is between + // the region limit and the global finger. + if (objAddr < _finger) { + return true; + } else if (objAddr < _region_limit) { + return false; + } // Else check global finger. + } + // Check global finger. + return objAddr < global_finger; +} inline void CMTask::deal_with_reference(oop obj) { if (_cm->verbose_high()) { @@ -297,50 +318,43 @@ // CAS done in CMBitMap::parMark() call in the routine above. HeapWord* global_finger = _cm->finger(); -#if _CHECK_BOTH_FINGERS_ - // we will check both the local and global fingers - - if (_finger != NULL && objAddr < _finger) { - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the local finger ("PTR_FORMAT"), " - "pushing it", _worker_id, p2i(_finger)); + // We only need to push a newly grey object on the mark + // stack if it is in a section of memory the mark bitmap + // scan has already examined. Mark bitmap scanning + // maintains progress "fingers" for determining that. + // + // Notice that the global finger might be moving forward + // concurrently. This is not a problem. In the worst case, we + // mark the object while it is above the global finger and, by + // the time we read the global finger, it has moved forward + // past this object. In this case, the object will probably + // be visited when a task is scanning the region and will also + // be pushed on the stack. So, some duplicate work, but no + // correctness problems. + if (is_below_finger(objAddr, global_finger)) { + if (obj->is_typeArray()) { + // Immediately process arrays of primitive types, rather + // than pushing on the mark stack. This keeps us from + // adding humongous objects to the mark stack that might + // be reclaimed before the entry is processed - see + // selection of candidates for eager reclaim of humongous + // objects. The cost of the additional type test is + // mitigated by avoiding a trip through the mark stack, + // by only doing a bookkeeping update and avoiding the + // actual scan of the object - a typeArray contains no + // references, and the metadata is built-in. + process_grey_object(obj); + } else { + if (_cm->verbose_high()) { + gclog_or_tty->print_cr("[%u] below a finger (local: " PTR_FORMAT + ", global: " PTR_FORMAT ") pushing " + PTR_FORMAT " on mark stack", + _worker_id, p2i(_finger), + p2i(global_finger), p2i(objAddr)); + } + push(obj); } - push(obj); - } else if (_curr_region != NULL && objAddr < _region_limit) { - // do nothing - } else if (objAddr < global_finger) { - // Notice that the global finger might be moving forward - // concurrently. This is not a problem. In the worst case, we - // mark the object while it is above the global finger and, by - // the time we read the global finger, it has moved forward - // passed this object. In this case, the object will probably - // be visited when a task is scanning the region and will also - // be pushed on the stack. So, some duplicate work, but no - // correctness problems. - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } else { - // do nothing } -#else // _CHECK_BOTH_FINGERS_ - // we will only check the global finger - - if (objAddr < global_finger) { - // see long comment above - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } -#endif // _CHECK_BOTH_FINGERS_ } } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -29,6 +29,9 @@ #include "gc_implementation/g1/g1AllocRegion.hpp" #include "gc_implementation/g1/g1InCSetState.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_interface/collectedHeap.hpp" + +class EvacuationInfo; // Base class for G1 allocators. class G1Allocator : public CHeapObj { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/space.hpp" @@ -303,9 +304,9 @@ assert(blk_start <= threshold, "blk_start should be at or before threshold"); assert(pointer_delta(threshold, blk_start) <= N_words, "offset should be <= BlockOffsetSharedArray::N"); - assert(Universe::heap()->is_in_reserved(blk_start), + assert(G1CollectedHeap::heap()->is_in_reserved(blk_start), "reference must be into the heap"); - assert(Universe::heap()->is_in_reserved(blk_end-1), + assert(G1CollectedHeap::heap()->is_in_reserved(blk_end-1), "limit must be within the heap"); assert(threshold == _array->_reserved.start() + index*N_words, "index must agree with threshold"); @@ -458,7 +459,7 @@ } HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold_raw() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); _next_offset_index = _array->index_for_raw(_bottom); _next_offset_index++; @@ -468,7 +469,7 @@ } void G1BlockOffsetArrayContigSpace::zero_bottom_entry_raw() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); size_t bottom_index = _array->index_for_raw(_bottom); assert(_array->address_for_index_raw(bottom_index) == _bottom, @@ -477,7 +478,7 @@ } HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); _next_offset_index = _array->index_for(_bottom); _next_offset_index++; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -70,6 +70,7 @@ #include "runtime/orderAccess.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/stack.inline.hpp" size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; @@ -1728,7 +1729,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : - SharedHeap(), + CollectedHeap(), _g1_policy(policy_), _dirty_card_queue_set(false), _into_cset_dirty_card_queue_set(false), @@ -1746,7 +1747,7 @@ _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()), _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()), - _humongous_is_live(), + _humongous_reclaim_candidates(), _has_humongous_reclaim_candidates(false), _free_regions_coming(false), _young_list(new YoungList(this)), @@ -1770,6 +1771,11 @@ _g1h = this; + _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); + _workers->initialize_workers(); + _allocator = G1Allocator::create_allocator(_g1h); _humongous_object_threshold_in_words = HeapRegion::GrainWords / 2; @@ -1797,6 +1803,26 @@ guarantee(_task_queues != NULL, "task_queues allocation failure."); } +G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor) { + size_t preferred_page_size = os::page_size_for_region_unaligned(size, 1); + // Allocate a new reserved space, preferring to use large pages. + ReservedSpace rs(size, preferred_page_size); + G1RegionToSpaceMapper* result = + G1RegionToSpaceMapper::create_mapper(rs, + size, + rs.alignment(), + HeapRegion::GrainBytes, + translation_factor, + mtGC); + if (TracePageSizes) { + gclog_or_tty->print_cr("G1 '%s': pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT " alignment=" SIZE_FORMAT " reqsize=" SIZE_FORMAT, + description, preferred_page_size, p2i(rs.base()), rs.size(), rs.alignment(), size); + } + return result; +} + jint G1CollectedHeap::initialize() { CollectedHeap::pre_initialize(); os::enable_vtime(); @@ -1864,57 +1890,35 @@ ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); G1RegionToSpaceMapper* heap_storage = G1RegionToSpaceMapper::create_mapper(g1_rs, + g1_rs.size(), UseLargePages ? os::large_page_size() : os::vm_page_size(), HeapRegion::GrainBytes, 1, mtJavaHeap); heap_storage->set_mapping_changed_listener(&_listener); - // Reserve space for the block offset table. We do not support automatic uncommit - // for the card table at this time. BOT only. - ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + // Create storage for the BOT, card table, card counts table (hot card cache) and the bitmaps. G1RegionToSpaceMapper* bot_storage = - G1RegionToSpaceMapper::create_mapper(bot_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); + create_aux_memory_mapper("Block offset table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize)); G1RegionToSpaceMapper* cardtable_storage = - G1RegionToSpaceMapper::create_mapper(cardtable_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for the card counts table. - ReservedSpace card_counts_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + create_aux_memory_mapper("Card table", + G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + G1RegionToSpaceMapper* card_counts_storage = - G1RegionToSpaceMapper::create_mapper(card_counts_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for prev and next bitmap. + create_aux_memory_mapper("Card counts table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + size_t bitmap_size = CMBitMap::compute_size(g1_rs.size()); - - ReservedSpace prev_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); G1RegionToSpaceMapper* prev_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(prev_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); - - ReservedSpace next_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); + create_aux_memory_mapper("Prev Bitmap", bitmap_size, CMBitMap::mark_distance()); G1RegionToSpaceMapper* next_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(next_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); + create_aux_memory_mapper("Next Bitmap", bitmap_size, CMBitMap::mark_distance()); _hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage); g1_barrier_set()->initialize(cardtable_storage); @@ -1937,8 +1941,14 @@ _g1h = this; - _in_cset_fast_test.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); - _humongous_is_live.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); + { + HeapWord* start = _hrm.reserved().start(); + HeapWord* end = _hrm.reserved().end(); + size_t granularity = HeapRegion::GrainBytes; + + _in_cset_fast_test.initialize(start, end, granularity); + _humongous_reclaim_candidates.initialize(start, end, granularity); + } // Create the ConcurrentMark data structure and thread. // (Must do this late, so that "max_regions" is defined.) @@ -2026,15 +2036,15 @@ } } -void G1CollectedHeap::clear_humongous_is_live_table() { - guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true"); - _humongous_is_live.clear(); -} - size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } +void G1CollectedHeap::post_initialize() { + CollectedHeap::post_initialize(); + ref_processing_init(); +} + void G1CollectedHeap::ref_processing_init() { // Reference processing in G1 currently works as follows: // @@ -2071,7 +2081,6 @@ // * Discovery is atomic - i.e. not concurrent. // * Reference discovery will not need a barrier. - SharedHeap::ref_processing_init(); MemRegion mr = reserved_region(); // Concurrent Mark ref processor @@ -2128,6 +2137,7 @@ } #ifndef PRODUCT + class CheckGCTimeStampsHRClosure : public HeapRegionClosure { private: unsigned _gc_time_stamp; @@ -2462,11 +2472,6 @@ } }; -void G1CollectedHeap::oop_iterate(ExtendedOopClosure* cl) { - IterateOopClosureRegionClosure blk(cl); - heap_region_iterate(&blk); -} - // Iterates an ObjectClosure over all objects within a HeapRegion. class IterateObjectClosureRegionClosure: public HeapRegionClosure { @@ -2486,23 +2491,6 @@ heap_region_iterate(&blk); } -// Calls a SpaceClosure on a HeapRegion. - -class SpaceClosureRegionClosure: public HeapRegionClosure { - SpaceClosure* _cl; -public: - SpaceClosureRegionClosure(SpaceClosure* cl) : _cl(cl) {} - bool doHeapRegion(HeapRegion* r) { - _cl->do_space(r); - return false; - } -}; - -void G1CollectedHeap::space_iterate(SpaceClosure* cl) { - SpaceClosureRegionClosure blk(cl); - heap_region_iterate(&blk); -} - void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const { _hrm.iterate(cl); } @@ -2639,23 +2627,19 @@ return result; } -Space* G1CollectedHeap::space_containing(const void* addr) const { - return heap_region_containing(addr); -} - HeapWord* G1CollectedHeap::block_start(const void* addr) const { - Space* sp = space_containing(addr); - return sp->block_start(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_start(addr); } size_t G1CollectedHeap::block_size(const HeapWord* addr) const { - Space* sp = space_containing(addr); - return sp->block_size(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_size(addr); } bool G1CollectedHeap::block_is_obj(const HeapWord* addr) const { - Space* sp = space_containing(addr); - return sp->block_is_obj(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_is_obj(addr); } bool G1CollectedHeap::supports_tlab_allocation() const { @@ -3336,8 +3320,8 @@ #endif // PRODUCT G1CollectedHeap* G1CollectedHeap::heap() { - assert(_sh->kind() == CollectedHeap::G1CollectedHeap, - "not a garbage-first heap"); + assert(_g1h != NULL, "Uninitialized access to G1CollectedHeap::heap()"); + assert(_g1h->kind() == CollectedHeap::G1CollectedHeap, "Not a G1 heap"); return _g1h; } @@ -3434,12 +3418,6 @@ return g1_rem_set()->cardsScanned(); } -bool G1CollectedHeap::humongous_region_is_always_live(uint index) { - HeapRegion* region = region_at(index); - assert(region->is_starts_humongous(), "Must start a humongous object"); - return oop(region->bottom())->is_objArray() || !region->rem_set()->is_empty(); -} - class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { private: size_t _total_humongous; @@ -3447,14 +3425,59 @@ DirtyCardQueue _dcq; - bool humongous_region_is_candidate(uint index) { - HeapRegion* region = G1CollectedHeap::heap()->region_at(index); - assert(region->is_starts_humongous(), "Must start a humongous object"); + // We don't nominate objects with many remembered set entries, on + // the assumption that such objects are likely still live. + bool is_remset_small(HeapRegion* region) const { HeapRegionRemSet* const rset = region->rem_set(); - bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs; - return !oop(region->bottom())->is_objArray() && - ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) || - (!allow_stale_refs && rset->is_empty())); + return G1EagerReclaimHumongousObjectsWithStaleRefs + ? rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries) + : rset->is_empty(); + } + + bool is_typeArray_region(HeapRegion* region) const { + return oop(region->bottom())->is_typeArray(); + } + + bool humongous_region_is_candidate(G1CollectedHeap* heap, HeapRegion* region) const { + assert(region->is_starts_humongous(), "Must start a humongous object"); + + // Candidate selection must satisfy the following constraints + // while concurrent marking is in progress: + // + // * In order to maintain SATB invariants, an object must not be + // reclaimed if it was allocated before the start of marking and + // has not had its references scanned. Such an object must have + // its references (including type metadata) scanned to ensure no + // live objects are missed by the marking process. Objects + // allocated after the start of concurrent marking don't need to + // be scanned. + // + // * An object must not be reclaimed if it is on the concurrent + // mark stack. Objects allocated after the start of concurrent + // marking are never pushed on the mark stack. + // + // Nominating only objects allocated after the start of concurrent + // marking is sufficient to meet both constraints. This may miss + // some objects that satisfy the constraints, but the marking data + // structures don't support efficiently performing the needed + // additional tests or scrubbing of the mark stack. + // + // However, we presently only nominate is_typeArray() objects. + // A humongous object containing references induces remembered + // set entries on other regions. In order to reclaim such an + // object, those remembered sets would need to be cleaned up. + // + // We also treat is_typeArray() objects specially, allowing them + // to be reclaimed even if allocated before the start of + // concurrent mark. For this we rely on mark stack insertion to + // exclude is_typeArray() objects, preventing reclaiming an object + // that is in the mark stack. We also rely on the metadata for + // such objects to be built-in and so ensured to be kept live. + // Frequent allocation and drop of large binary blobs is an + // important use case for eager reclaim, and this special handling + // may reduce needed headroom. + + return is_typeArray_region(region) && is_remset_small(region); } public: @@ -3470,14 +3493,17 @@ } G1CollectedHeap* g1h = G1CollectedHeap::heap(); - uint region_idx = r->hrm_index(); - bool is_candidate = humongous_region_is_candidate(region_idx); - // Is_candidate already filters out humongous object with large remembered sets. - // If we have a humongous object with a few remembered sets, we simply flush these - // remembered set entries into the DCQS. That will result in automatic - // re-evaluation of their remembered set entries during the following evacuation - // phase. + bool is_candidate = humongous_region_is_candidate(g1h, r); + uint rindex = r->hrm_index(); + g1h->set_humongous_reclaim_candidate(rindex, is_candidate); if (is_candidate) { + _candidate_humongous++; + g1h->register_humongous_region_with_cset(rindex); + // Is_candidate already filters out humongous object with large remembered sets. + // If we have a humongous object with a few remembered sets, we simply flush these + // remembered set entries into the DCQS. That will result in automatic + // re-evaluation of their remembered set entries during the following evacuation + // phase. if (!r->rem_set()->is_empty()) { guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), "Found a not-small remembered set here. This is inconsistent with previous assumptions."); @@ -3499,8 +3525,6 @@ r->rem_set()->clear_locked(); } assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); - g1h->register_humongous_region_with_cset(region_idx); - _candidate_humongous++; } _total_humongous++; @@ -3520,6 +3544,7 @@ } double time = os::elapsed_counter(); + // Collect reclaim candidate information and register candidates with cset. RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); @@ -3529,10 +3554,6 @@ cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; - if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) { - clear_humongous_is_live_table(); - } - // Finally flush all remembered set entries to re-check into the global DCQS. cl.flush_rem_set_entries(); } @@ -5994,11 +6015,11 @@ // required because stale remembered sets might reference locations that // are currently allocated into. uint region_idx = r->hrm_index(); - if (g1h->humongous_is_live(region_idx) || - g1h->humongous_region_is_always_live(region_idx)) { + if (!g1h->is_humongous_reclaim_candidate(region_idx) || + !r->rem_set()->is_empty()) { if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", region_idx, obj->size()*HeapWordSize, r->bottom(), @@ -6006,20 +6027,21 @@ r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } return false; } - guarantee(!obj->is_objArray(), - err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", + guarantee(obj->is_typeArray(), + err_msg("Only eagerly reclaiming type arrays is supported, but the object " + PTR_FORMAT " is not.", r->bottom())); if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", region_idx, obj->size()*HeapWordSize, r->bottom(), @@ -6027,8 +6049,8 @@ r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } // Need to clear mark bit of the humongous object if already set. @@ -6163,8 +6185,6 @@ } void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) { - assert(heap_lock_held_for_gc(), - "the heap lock should already be held by or for this thread"); _young_list->push_region(hr); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -40,9 +40,9 @@ #include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/shared/hSpaceCounters.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/barrierSet.hpp" #include "memory/memRegion.hpp" -#include "memory/sharedHeap.hpp" #include "utilities/stack.hpp" // A "G1CollectedHeap" is an implementation of a java heap for HotSpot. @@ -76,6 +76,7 @@ class EvacuationFailedInfo; class nmethod; class Ticks; +class FlexibleWorkGang; typedef OverflowTaskQueue RefToScanQueue; typedef GenericTaskQueueSet RefToScanQueueSet; @@ -177,7 +178,7 @@ virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; -class G1CollectedHeap : public SharedHeap { +class G1CollectedHeap : public CollectedHeap { friend class VM_CollectForMetadataAllocation; friend class VM_G1CollectForAllocation; friend class VM_G1CollectFull; @@ -204,6 +205,8 @@ // The one and only G1CollectedHeap, so static functions can find it. static G1CollectedHeap* _g1h; + FlexibleWorkGang* _workers; + static size_t _humongous_object_threshold_in_words; // The secondary free list which contains regions that have been @@ -217,7 +220,6 @@ // It keeps track of the humongous regions. HeapRegionSet _humongous_set; - void clear_humongous_is_live_table(); void eagerly_reclaim_humongous_regions(); // The number of regions we could create by expansion. @@ -287,22 +289,26 @@ // Helper for monitoring and management support. G1MonitoringSupport* _g1mm; - // Records whether the region at the given index is kept live by roots or - // references from the young generation. - class HumongousIsLiveBiasedMappedArray : public G1BiasedMappedArray { + // Records whether the region at the given index is (still) a + // candidate for eager reclaim. Only valid for humongous start + // regions; other regions have unspecified values. Humongous start + // regions are initialized at start of collection pause, with + // candidates removed from the set as they are found reachable from + // roots or the young generation. + class HumongousReclaimCandidates : public G1BiasedMappedArray { protected: bool default_value() const { return false; } public: void clear() { G1BiasedMappedArray::clear(); } - void set_live(uint region) { - set_by_index(region, true); + void set_candidate(uint region, bool value) { + set_by_index(region, value); } - bool is_live(uint region) { + bool is_candidate(uint region) { return get_by_index(region); } }; - HumongousIsLiveBiasedMappedArray _humongous_is_live; + HumongousReclaimCandidates _humongous_reclaim_candidates; // Stores whether during humongous object registration we found candidate regions. // If not, we can skip a few steps. bool _has_humongous_reclaim_candidates; @@ -351,6 +357,12 @@ // heap after a compaction. void print_hrm_post_compaction(); + // Create a memory mapper for auxiliary data structures of the given size and + // translation factor. + static G1RegionToSpaceMapper* create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor); + double verify(bool guard, const char* msg); void verify_before_gc(); void verify_after_gc(); @@ -605,6 +617,7 @@ void enqueue_discovered_references(uint no_of_gc_workers); public: + FlexibleWorkGang* workers() const { return _workers; } G1Allocator* allocator() { return _allocator; @@ -630,21 +643,18 @@ inline AllocationContextStats& allocation_context_stats(); // Do anything common to GC's. - virtual void gc_prologue(bool full); - virtual void gc_epilogue(bool full); + void gc_prologue(bool full); + void gc_epilogue(bool full); + // Modify the reclaim candidate set and test for presence. + // These are only valid for starts_humongous regions. + inline void set_humongous_reclaim_candidate(uint region, bool value); + inline bool is_humongous_reclaim_candidate(uint region); + + // Remove from the reclaim candidate set. Also remove from the + // collection set so that later encounters avoid the slow path. inline void set_humongous_is_live(oop obj); - bool humongous_is_live(uint region) { - return _humongous_is_live.is_live(region); - } - - // Returns whether the given region (which must be a humongous (start) region) - // is to be considered conservatively live regardless of any other conditions. - bool humongous_region_is_always_live(uint index); - // Returns whether the given region (which must be a humongous (start) region) - // is considered a candidate for eager reclamation. - bool humongous_region_is_candidate(uint index); // Register the given region to be part of the collection set. inline void register_humongous_region_with_cset(uint index); // Register regions with humongous objects (actually on the start region) in @@ -1000,11 +1010,14 @@ // Return the (conservative) maximum heap alignment for any G1 heap static size_t conservative_max_heap_alignment(); + // Does operations required after initialization has been done. + void post_initialize(); + // Initialize weak reference processing. - virtual void ref_processing_init(); + void ref_processing_init(); // Explicitly import set_par_threads into this scope - using SharedHeap::set_par_threads; + using CollectedHeap::set_par_threads; // Set _n_par_threads according to a policy TBD. void set_par_threads(); @@ -1251,10 +1264,6 @@ // Iteration functions. - // Iterate over all the ref-containing fields of all objects, calling - // "cl.do_oop" on each. - virtual void oop_iterate(ExtendedOopClosure* cl); - // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl); @@ -1262,9 +1271,6 @@ object_iterate(cl); } - // Iterate over all spaces in use in the heap, in ascending address order. - virtual void space_iterate(SpaceClosure* cl); - // Iterate over heap regions, in address order, terminating the // iteration early if the "doHeapRegion" method returns "true". void heap_region_iterate(HeapRegionClosure* blk) const; @@ -1307,10 +1313,6 @@ HeapRegion* next_compaction_region(const HeapRegion* from) const; - // A CollectedHeap will contain some number of spaces. This finds the - // space containing a given address, or else returns NULL. - virtual Space* space_containing(const void* addr) const; - // Returns the HeapRegion that contains addr. addr must not be NULL. template inline HeapRegion* heap_region_containing_raw(const T addr) const; @@ -1344,9 +1346,6 @@ // the block is an object. virtual bool block_is_obj(const HeapWord* addr) const; - // Does this heap support heap inspection? (+PrintClassHistogram) - virtual bool supports_heap_inspection() const { return true; } - // Section on thread-local allocation buffers (TLABs) // See CollectedHeap for semantics. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -352,20 +352,30 @@ return is_obj_ill(obj, heap_region_containing(obj)); } +inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { + assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); + _humongous_reclaim_candidates.set_candidate(region, value); +} + +inline bool G1CollectedHeap::is_humongous_reclaim_candidate(uint region) { + assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); + return _humongous_reclaim_candidates.is_candidate(region); +} + inline void G1CollectedHeap::set_humongous_is_live(oop obj) { uint region = addr_to_region((HeapWord*)obj); - // We not only set the "live" flag in the humongous_is_live table, but also + // Clear the flag in the humongous_reclaim_candidates table. Also // reset the entry in the _in_cset_fast_test table so that subsequent references // to the same humongous object do not go into the slow path again. // This is racy, as multiple threads may at the same time enter here, but this // is benign. - // During collection we only ever set the "live" flag, and only ever clear the + // During collection we only ever clear the "candidate" flag, and only ever clear the // entry in the in_cset_fast_table. // We only ever evaluate the contents of these tables (in the VM thread) after // having synchronized the worker threads with the VM thread, or in the same // thread (i.e. within the VM thread). - if (!_humongous_is_live.is_live(region)) { - _humongous_is_live.set_live(region); + if (is_humongous_reclaim_candidate(region)) { + set_humongous_reclaim_candidate(region, false); _in_cset_fast_test.clear_humongous(region); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1460,7 +1460,7 @@ _max_survivor_regions = (uint) ceil(max_survivor_regions_d); _tenuring_threshold = _survivors_age_table.compute_tenuring_threshold( - HeapRegion::GrainWords * _max_survivor_regions); + HeapRegion::GrainWords * _max_survivor_regions, counters()); } bool G1CollectorPolicy::force_initial_mark_if_outside_cycle( diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,7 +263,6 @@ _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[CodeCacheRoots] = new WorkerDataArray(max_gc_threads, "CodeCache Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms)", true, G1Log::LevelFinest, 3); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,6 @@ SystemDictionaryRoots, CLDGRoots, JVMTIRoots, - CodeCacheRoots, CMRefRoots, WaitForStrongCLD, WeakCLDRoots, diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -29,7 +29,7 @@ #include "gc_implementation/g1/g1CardCounts.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/globalDefinitions.hpp" class DirtyCardQueue; @@ -123,7 +123,7 @@ // Resets the hot card cache and discards the entries. void reset_hot_cache() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); - assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread"); + assert(Thread::current_noinline()->is_VM_thread(), "Current thread should be the VMthread"); if (default_use_cache()) { reset_hot_cache_internal(); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -61,9 +61,8 @@ bool clear_all_softrefs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - SharedHeap* sh = SharedHeap::heap(); #ifdef ASSERT - if (sh->collector_policy()->should_clear_all_soft_refs()) { + if (G1CollectedHeap::heap()->collector_policy()->should_clear_all_soft_refs()) { assert(clear_all_softrefs, "Policy should have been checked earler"); } #endif @@ -102,11 +101,6 @@ BiasedLocking::restore_marks(); GenMarkSweep::deallocate_stacks(); - // "free at last gc" is calculated from these. - // CHF: cheating for now!!! - // Universe::set_heap_capacity_at_last_gc(Universe::heap()->capacity()); - // Universe::set_heap_used_at_last_gc(Universe::heap()->used()); - CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); @@ -168,12 +162,12 @@ Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. - G1CollectedHeap::heap()->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); + g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); if (VerifyDuringGC) { HandleMark hm; // handle scope COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including // identity hash values, ages, etc) is preserved, and the mark @@ -187,7 +181,7 @@ if (!VerifySilently) { gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying "); } - Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord); + g1h->verify(VerifySilently, VerifyOption_G1UseMarkWord); if (!VerifySilently) { gclog_or_tty->print_cr("]"); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1MARKSWEEP_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1MARKSWEEP_HPP -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/genMarkSweep.hpp" #include "memory/generation.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,9 +23,12 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1_specialized_oop_closures.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1ParScanThreadState.hpp" +#include "memory/iterator.inline.hpp" +#include "utilities/stack.inline.hpp" G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : G1ParClosureSuper(g1, par_scan_state), _scanned_klass(NULL), @@ -50,3 +53,6 @@ assert(_worker_id < MAX2((uint)ParallelGCThreads, 1u), err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, MAX2((uint)ParallelGCThreads, 1u))); } + +// Generate G1 specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,7 +172,7 @@ oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(_g1->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(_from != NULL, "from region must be non-NULL"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,37 +44,45 @@ #endif #include "utilities/bitMap.inline.hpp" -G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), - _high_boundary(NULL), _committed(), _page_size(0), _special(false), +G1PageBasedVirtualSpace::G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size) : + _low_boundary(NULL), _high_boundary(NULL), _committed(), _page_size(0), _special(false), _dirty(), _executable(false) { + initialize_with_page_size(rs, used_size, page_size); } -bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { - if (!rs.is_reserved()) { - return false; // Allocation failed. - } - assert(_low_boundary == NULL, "VirtualSpace already initialized"); - assert(page_size > 0, "Granularity must be non-zero."); +void G1PageBasedVirtualSpace::initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size) { + guarantee(rs.is_reserved(), "Given reserved space must have been reserved already."); + + vmassert(_low_boundary == NULL, "VirtualSpace already initialized"); + vmassert(page_size > 0, "Page size must be non-zero."); + + guarantee(is_ptr_aligned(rs.base(), page_size), + err_msg("Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size)); + guarantee(is_size_aligned(used_size, os::vm_page_size()), + err_msg("Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size)); + guarantee(used_size <= rs.size(), + err_msg("Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size())); + guarantee(is_size_aligned(rs.size(), page_size), + err_msg("Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size)); _low_boundary = rs.base(); - _high_boundary = _low_boundary + rs.size(); + _high_boundary = _low_boundary + used_size; _special = rs.special(); _executable = rs.executable(); _page_size = page_size; - assert(_committed.size() == 0, "virtual space initialized more than once"); - uintx size_in_bits = rs.size() / page_size; - _committed.resize(size_in_bits, /* in_resource_area */ false); + vmassert(_committed.size() == 0, "virtual space initialized more than once"); + BitMap::idx_t size_in_pages = rs.size() / page_size; + _committed.resize(size_in_pages, /* in_resource_area */ false); if (_special) { - _dirty.resize(size_in_bits, /* in_resource_area */ false); + _dirty.resize(size_in_pages, /* in_resource_area */ false); } - return true; + _tail_size = used_size % _page_size; } - G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() { release(); } @@ -87,12 +95,18 @@ _special = false; _executable = false; _page_size = 0; + _tail_size = 0; _committed.resize(0, false); _dirty.resize(0, false); } size_t G1PageBasedVirtualSpace::committed_size() const { - return _committed.count_one_bits() * _page_size; + size_t result = _committed.count_one_bits() * _page_size; + // The last page might not be in full. + if (is_last_page_partial() && _committed.at(_committed.size() - 1)) { + result -= _page_size - _tail_size; + } + return result; } size_t G1PageBasedVirtualSpace::reserved_size() const { @@ -103,65 +117,134 @@ return reserved_size() - committed_size(); } -uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { +size_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { return (addr - _low_boundary) / _page_size; } -bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_zero_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_committed(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_zero_offset(start_page, end_page) >= end_page; } -bool G1PageBasedVirtualSpace::is_area_uncommitted(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_one_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_uncommitted(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_one_offset(start_page, end_page) >= end_page; } -char* G1PageBasedVirtualSpace::page_start(uintptr_t index) { +char* G1PageBasedVirtualSpace::page_start(size_t index) const { return _low_boundary + index * _page_size; } -size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) { - return num * _page_size; +bool G1PageBasedVirtualSpace::is_after_last_page(size_t index) const { + guarantee(index <= _committed.size(), + err_msg("Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size())); + return index == _committed.size(); +} + +void G1PageBasedVirtualSpace::commit_preferred_pages(size_t start, size_t num_pages) { + vmassert(num_pages > 0, "No full pages to commit"); + vmassert(start + num_pages <= _committed.size(), + err_msg("Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " + "that is outside of managed space of " SIZE_FORMAT " pages", + start, start + num_pages, _committed.size())); + + char* start_addr = page_start(start); + size_t size = num_pages * _page_size; + + os::commit_memory_or_exit(start_addr, size, _page_size, _executable, + err_msg("Failed to commit area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(start_addr), p2i(start_addr + size), size)); +} + +void G1PageBasedVirtualSpace::commit_tail() { + vmassert(_tail_size > 0, "The size of the tail area must be > 0 when reaching here"); + + char* const aligned_end_address = (char*)align_ptr_down(_high_boundary, _page_size); + os::commit_memory_or_exit(aligned_end_address, _tail_size, os::vm_page_size(), _executable, + err_msg("Failed to commit tail area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); } -bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { +void G1PageBasedVirtualSpace::commit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + guarantee(end_page <= _committed.size(), + err_msg("Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size())); + + size_t pages = end_page - start_page; + bool need_to_commit_tail = is_after_last_page(end_page) && is_last_page_partial(); + + // If we have to commit some (partial) tail area, decrease the amount of pages to avoid + // committing that in the full-page commit code. + if (need_to_commit_tail) { + pages--; + } + + if (pages > 0) { + commit_preferred_pages(start_page, pages); + } + + if (need_to_commit_tail) { + commit_tail(); + } +} + +char* G1PageBasedVirtualSpace::bounded_end_addr(size_t end_page) const { + return MIN2(_high_boundary, page_start(end_page)); +} + +void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + + os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); +} + +bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { // We need to make sure to commit all pages covered by the given area. - guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted"); + guarantee(is_area_uncommitted(start_page, size_in_pages), "Specified area is not uncommitted"); bool zero_filled = true; - uintptr_t end = start + size_in_pages; + size_t end_page = start_page + size_in_pages; if (_special) { // Check for dirty pages and update zero_filled if any found. - if (_dirty.get_next_one_offset(start,end) < end) { + if (_dirty.get_next_one_offset(start_page, end_page) < end_page) { zero_filled = false; - _dirty.clear_range(start, end); + _dirty.clear_range(start_page, end_page); } } else { - os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable, - err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages)); + commit_internal(start_page, end_page); } - _committed.set_range(start, end); + _committed.set_range(start_page, end_page); if (AlwaysPreTouch) { - os::pretouch_memory(page_start(start), page_start(end)); + pretouch_internal(start_page, end_page); } return zero_filled; } -void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { - guarantee(is_area_committed(start, size_in_pages), "checking"); +void G1PageBasedVirtualSpace::uncommit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + char* start_addr = page_start(start_page); + os::uncommit_memory(start_addr, pointer_delta(bounded_end_addr(end_page), start_addr, sizeof(char))); +} + +void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) { + guarantee(is_area_committed(start_page, size_in_pages), "checking"); + + size_t end_page = start_page + size_in_pages; if (_special) { // Mark that memory is dirty. If committed again the memory might // need to be cleared explicitly. - _dirty.set_range(start, start + size_in_pages); + _dirty.set_range(start_page, end_page); } else { - os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); + uncommit_internal(start_page, end_page); } - _committed.clear_range(start, start + size_in_pages); + _committed.clear_range(start_page, end_page); } bool G1PageBasedVirtualSpace::contains(const void* p) const { @@ -175,7 +258,8 @@ out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); + out->print_cr(" - preferred page size: " SIZE_FORMAT, _page_size); + out->print_cr(" - [low_b, high_b]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); } void G1PageBasedVirtualSpace::print() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -34,6 +34,12 @@ // granularity. // (De-)Allocation requests are always OS page aligned by passing a page index // and multiples of pages. +// For systems that only commits of memory in a given size (always greater than +// page size) the base address is required to be aligned to that page size. +// The actual size requested need not be aligned to that page size, but the size +// of the reservation passed may be rounded up to this page size. Any fragment +// (less than the page size) of the actual size at the tail of the request will +// be committed using OS small pages. // The implementation gives an error when trying to commit or uncommit pages that // have already been committed or uncommitted. class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC { @@ -43,7 +49,11 @@ char* _low_boundary; char* _high_boundary; - // The commit/uncommit granularity in bytes. + // The size of the tail in bytes of the handled space that needs to be committed + // using small pages. + size_t _tail_size; + + // The preferred page size used for commit/uncommit in bytes. size_t _page_size; // Bitmap used for verification of commit/uncommit operations. @@ -62,30 +72,55 @@ // Indicates whether the committed space should be executable. bool _executable; + // Helper function for committing memory. Commit the given memory range by using + // _page_size pages as much as possible and the remainder with small sized pages. + void commit_internal(size_t start_page, size_t end_page); + // Commit num_pages pages of _page_size size starting from start. All argument + // checking has been performed. + void commit_preferred_pages(size_t start_page, size_t end_page); + // Commit space at the high end of the space that needs to be committed with small + // sized pages. + void commit_tail(); + + // Uncommit the given memory range. + void uncommit_internal(size_t start_page, size_t end_page); + + // Pretouch the given memory range. + void pretouch_internal(size_t start_page, size_t end_page); + // Returns the index of the page which contains the given address. uintptr_t addr_to_page_index(char* addr) const; // Returns the address of the given page index. - char* page_start(uintptr_t index); - // Returns the byte size of the given number of pages. - size_t byte_size_for_pages(size_t num); + char* page_start(size_t index) const; + + // Is the given page index the last page? + bool is_last_page(size_t index) const { return index == (_committed.size() - 1); } + // Is the given page index the first after last page? + bool is_after_last_page(size_t index) const; + // Is the last page only partially covered by this space? + bool is_last_page_partial() const { return !is_ptr_aligned(_high_boundary, _page_size); } + // Returns the end address of the given page bounded by the reserved space. + char* bounded_end_addr(size_t end_page) const; // Returns true if the entire area is backed by committed memory. - bool is_area_committed(uintptr_t start, size_t size_in_pages) const; + bool is_area_committed(size_t start_page, size_t size_in_pages) const; // Returns true if the entire area is not backed by committed memory. - bool is_area_uncommitted(uintptr_t start, size_t size_in_pages) const; + bool is_area_uncommitted(size_t start_page, size_t size_in_pages) const; + void initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size); public: // Commit the given area of pages starting at start being size_in_pages large. // Returns true if the given area is zero filled upon completion. - bool commit(uintptr_t start, size_t size_in_pages); + bool commit(size_t start_page, size_t size_in_pages); // Uncommit the given area of pages starting at start being size_in_pages large. - void uncommit(uintptr_t start, size_t size_in_pages); + void uncommit(size_t start_page, size_t size_in_pages); - // Initialization - G1PageBasedVirtualSpace(); - bool initialize_with_granularity(ReservedSpace rs, size_t page_size); + // Initialize the given reserved space with the given base address and the size + // actually used. + // Prefer to commit in page_size chunks. + G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size); // Destruction ~G1PageBasedVirtualSpace(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,8 +26,10 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" +#include "utilities/stack.inline.hpp" G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp) : _g1h(g1h), diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ assert(has_partial_array_mask(p), "invariant"); oop from_obj = clear_partial_array_mask(p); - assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); objArrayOop from_obj_array = objArrayOop(from_obj); // The from-space object contains the real length. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,17 +31,16 @@ #include "utilities/bitMap.inline.hpp" G1RegionToSpaceMapper::G1RegionToSpaceMapper(ReservedSpace rs, - size_t commit_granularity, + size_t used_size, + size_t page_size, size_t region_granularity, MemoryType type) : - _storage(), - _commit_granularity(commit_granularity), + _storage(rs, used_size, page_size), _region_granularity(region_granularity), _listener(NULL), _commit_map() { - guarantee(is_power_of_2(commit_granularity), "must be"); + guarantee(is_power_of_2(page_size), "must be"); guarantee(is_power_of_2(region_granularity), "must be"); - _storage.initialize_with_granularity(rs, commit_granularity); MemTracker::record_virtual_memory_type((address)rs.base(), type); } @@ -55,25 +54,26 @@ public: G1RegionsLargerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _pages_per_region(alloc_granularity / (os_commit_granularity * commit_factor)) { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _pages_per_region(alloc_granularity / (page_size * commit_factor)) { - guarantee(alloc_granularity >= os_commit_granularity, "allocation granularity smaller than commit granularity"); + guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity"); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - bool zero_filled = _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void commit_regions(uint start_idx, size_t num_regions) { + bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.set_range(start_idx, start_idx + num_regions); fire_on_commit(start_idx, num_regions, zero_filled); } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - _storage.uncommit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + _storage.uncommit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.clear_range(start_idx, start_idx + num_regions); } }; @@ -98,22 +98,23 @@ public: G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _regions_per_page((os_commit_granularity * commit_factor) / alloc_granularity), _refcounts() { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _regions_per_page((page_size * commit_factor) / alloc_granularity), _refcounts() { - guarantee((os_commit_granularity * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); - _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + rs.size()), os_commit_granularity); + guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); + _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void commit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; if (old_refcount == 0) { @@ -125,10 +126,10 @@ } } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region "INTPTR_FORMAT" that is not committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); assert(old_refcount > 0, "must be"); if (old_refcount == 1) { @@ -147,14 +148,15 @@ } G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t commit_factor, MemoryType type) { - if (region_granularity >= (os_commit_granularity * commit_factor)) { - return new G1RegionsLargerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + if (region_granularity >= (page_size * commit_factor)) { + return new G1RegionsLargerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } else { - return new G1RegionsSmallerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + return new G1RegionsSmallerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -46,12 +46,12 @@ protected: // Backing storage. G1PageBasedVirtualSpace _storage; - size_t _commit_granularity; + size_t _region_granularity; // Mapping management BitMap _commit_map; - G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type); + G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, MemoryType type); void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); public: @@ -70,16 +70,20 @@ return _commit_map.at(idx); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; + virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0; + virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0; // Creates an appropriate G1RegionToSpaceMapper for the given parameters. + // The actual space to be used within the given reservation is given by actual_size. + // This is because some OSes need to round up the reservation size to guarantee + // alignment of page_size. // The byte_translation_factor defines how many bytes in a region correspond to // a single byte in the data structure this mapper is for. // Eg. in the card table, this value corresponds to the size a single card - // table entry corresponds to. + // table entry corresponds to in the heap. static G1RegionToSpaceMapper* create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t byte_translation_factor, MemoryType type); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -38,6 +38,7 @@ #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/intHisto.hpp" +#include "utilities/stack.inline.hpp" #define CARD_REPEAT_HISTO 0 diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(_g1->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(from == NULL || from->is_in_reserved(p), "p is not in from"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -116,7 +116,7 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) : _g1h(g1h), _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)), - _srs(g1h), + _srs(), _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never), _n_workers_discovered_strong_classes(0) {} @@ -253,7 +253,8 @@ { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i); - Threads::possibly_parallel_oops_do(strong_roots, thread_stack_clds, strong_code); + bool is_par = _g1h->n_par_threads() > 0; + Threads::possibly_parallel_oops_do(is_par, strong_roots, thread_stack_clds, strong_code); } } @@ -323,10 +324,6 @@ void G1RootProcessor::scan_remembered_sets(G1ParPushHeapRSClosure* scan_rs, OopClosure* scan_non_heap_weak_roots, uint worker_i) { - G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); - G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CodeCacheRoots, worker_i); - - // Now scan the complement of the collection set. G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots); _g1h->g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,7 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_ROOTPROCESSOR_HPP #include "memory/allocation.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "runtime/mutex.hpp" class CLDClosure; @@ -46,7 +46,7 @@ class G1RootProcessor : public StackObj { G1CollectedHeap* _g1h; SubTasksDone* _process_strong_tasks; - SharedHeap::StrongRootsScope _srs; + StrongRootsScope _srs; // Used to implement the Thread work barrier. Monitor _lock; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -206,7 +206,7 @@ if (new_val == NULL) return; // Otherwise, log it. G1SATBCardTableLoggingModRefBS* g1_bs = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(G1CollectedHeap::heap()->barrier_set()); g1_bs->write_ref_field_work(field, new_val); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1StringDedupQueue.hpp" #include "memory/gcLocker.hpp" @@ -163,7 +164,7 @@ while (!iter.is_empty()) { oop obj = iter.next(); if (obj != NULL) { - guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); + guarantee(G1CollectedHeap::heap()->is_in_reserved(obj), "Object must be on the heap"); guarantee(!obj->is_forwarded(), "Object must not be forwarded"); guarantee(java_lang_String::is_instance(obj), "Object must be a String"); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -27,6 +27,7 @@ #include "classfile/javaClasses.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1StringDedupTable.hpp" #include "memory/gcLocker.hpp" #include "memory/padded.inline.hpp" @@ -519,7 +520,7 @@ while (*entry != NULL) { typeArrayOop value = (*entry)->obj(); guarantee(value != NULL, "Object must not be NULL"); - guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); + guarantee(G1CollectedHeap::heap()->is_in_reserved(value), "Object must be on the heap"); guarantee(!value->is_forwarded(), "Object must not be forwarded"); guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); unsigned int hash = hash_code(value); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -29,6 +29,7 @@ #include "runtime/mutexLocker.hpp" class G1StringDedupEntryCache; +class G1StringDedupUnlinkOrOopsDoClosure; // // Table entry in the deduplication hashtable. Points weakly to the diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -31,7 +31,6 @@ #include "gc_implementation/g1/survRateGroup.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" -#include "memory/space.inline.hpp" #include "memory/watermark.hpp" #include "utilities/macros.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -330,8 +330,12 @@ assert(!hrclaimer->is_region_claimed(ch_index), "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); - // There's no need to actually claim the continues humongous region, but we can do it in an assert as an extra precaution. - assert(hrclaimer->claim_region(ch_index), "We should always be able to claim the continuesHumongous part of the humongous object"); + // Claim the region so no other worker tries to process the region. When a worker processes a + // starts_humongous region it may also process the associated continues_humongous regions. + // The continues_humongous regions can be changed to free regions. Unless this worker claims + // all of these regions, other workers might try claim and process these newly free regions. + bool claim_result = hrclaimer->claim_region(ch_index); + guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object"); bool res2 = blk->doHeapRegion(chr); if (res2) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -419,6 +419,7 @@ ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size())); G1RegionToSpaceMapper* bot_storage = G1RegionToSpaceMapper::create_mapper(bot_rs, + bot_rs.size(), os::vm_page_size(), HeapRegion::GrainBytes, G1BlockOffsetSharedArray::N_bytes, diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/satbQueue.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" -#include "memory/sharedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,8 +26,8 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_VMSTRUCTS_G1_HPP #include "gc_implementation/g1/heapRegion.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/heapRegionManager.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #define VM_STRUCTS_G1(nonstatic_field, static_field) \ \ @@ -70,7 +70,7 @@ \ declare_toplevel_type(G1HeapRegionTable) \ \ - declare_type(G1CollectedHeap, SharedHeap) \ + declare_type(G1CollectedHeap, CollectedHeap) \ \ declare_type(G1OffsetTableContigSpace, CompactibleSpace) \ declare_type(HeapRegion, G1OffsetTableContigSpace) \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -225,15 +225,10 @@ void VM_CGC_Operation::doit() { TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); - GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm(), G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()); - SharedHeap* sh = SharedHeap::heap(); - // This could go away if CollectedHeap gave access to _gc_is_active... - if (sh != NULL) { - IsGCActiveMark x; - _cl->do_void(); - } else { - _cl->do_void(); - } + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm(), g1h->concurrent_mark()->concurrent_gc_id()); + IsGCActiveMark x; + _cl->do_void(); } bool VM_CGC_Operation::doit_prologue() { @@ -244,14 +239,12 @@ } Heap_lock->lock(); - SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true; return true; } void VM_CGC_Operation::doit_epilogue() { // Note the relative order of the unlocks must match that in // VM_GC_Operation::doit_epilogue() - SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false; Heap_lock->unlock(); if (_needs_pll) { release_and_notify_pending_list_lock(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,12 +23,12 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/cardTableRS.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/space.inline.hpp" -#include "memory/universe.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" @@ -449,7 +449,7 @@ // Do a dirty read here. If we pass the conditional then take the rare // event lock and do the read again in case some other thread had already // succeeded and done the resize. - int cur_collection = Universe::heap()->total_collections(); + int cur_collection = GenCollectedHeap::heap()->total_collections(); if (_last_LNC_resizing_collection[i] != cur_collection) { MutexLocker x(ParGCRareEvent_lock); if (_last_LNC_resizing_collection[i] != cur_collection) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -42,7 +42,7 @@ #include "memory/generation.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/space.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" @@ -53,6 +53,7 @@ #include "runtime/thread.inline.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/stack.inline.hpp" #include "utilities/workgroup.hpp" #ifdef _MSC_VER @@ -117,7 +118,7 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { assert(old->is_objArray(), "must be obj array"); assert(old->is_forwarded(), "must be forwarded"); - assert(Universe::heap()->is_in_reserved(old), "must be in heap."); + assert(GenCollectedHeap::heap()->is_in_reserved(old), "must be in heap."); assert(!old_gen()->is_in(old), "must be in young generation."); objArrayOop obj = objArrayOop(old->forwardee()); @@ -199,9 +200,9 @@ for (size_t i = 0; i != num_take_elems; i++) { oop cur = of_stack->pop(); oop obj_to_push = cur->forwardee(); - assert(Universe::heap()->is_in_reserved(cur), "Should be in heap"); + assert(GenCollectedHeap::heap()->is_in_reserved(cur), "Should be in heap"); assert(!old_gen()->is_in_reserved(cur), "Should be in young gen"); - assert(Universe::heap()->is_in_reserved(obj_to_push), "Should be in heap"); + assert(GenCollectedHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap"); if (should_be_partially_scanned(obj_to_push, cur)) { assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); obj_to_push = cur; @@ -596,8 +597,6 @@ // and handle marks. ResourceMark rm; HandleMark hm; - // We would need multiple old-gen queues otherwise. - assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); ParScanThreadState& par_scan_state = _state_set->thread_state(worker_id); assert(_state_set->is_valid(worker_id), "Should not have been called"); @@ -697,7 +696,7 @@ _par_cl->do_oop_nv(p); - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -724,7 +723,7 @@ _cl->do_oop_nv(p); - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -823,8 +822,6 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) { GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "not a generational heap"); FlexibleWorkGang* workers = gch->workers(); assert(workers != NULL, "Need parallel worker threads."); _state_set.reset(workers->active_workers(), _generation.promotion_failed()); @@ -899,7 +896,7 @@ _gc_tracer.report_promotion_failed(_promotion_failed_info); } // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(gch->reset_promotion_should_fail();) } void ParNewGeneration::collect(bool full, @@ -912,8 +909,6 @@ _gc_timer->register_gc_start(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "not a CMS generational heap"); AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); FlexibleWorkGang* workers = gch->workers(); assert(workers != NULL, "Need workgang for parallel work"); @@ -922,8 +917,6 @@ workers->active_workers(), Threads::number_of_non_daemon_threads()); workers->set_active_workers(active_workers); - assert(gch->n_gens() == 2, - "Par collection currently only works with single older gen."); _old_gen = gch->old_gen(); // If the next generation is too full to accommodate worst-case promotion @@ -974,10 +967,10 @@ // in the multi-threaded case, but we special-case n=1 here to get // repeatable measurements of the 1-thread overhead of the parallel code. if (n_workers > 1) { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } thread_state_set.reset(0 /* Bad value in debug if not reset */, @@ -1194,7 +1187,7 @@ } else { // Is in to-space; do copying ourselves. Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz); - assert(Universe::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); + assert(GenCollectedHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); forward_ptr = old->forward_to_atomic(new_obj); // Restore the mark word copied above. new_obj->set_mark(m); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" +#include "gc_implementation/parNew/parOopClosures.inline.hpp" + +// Generate ParNew specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(ALL_KLASS_OOP_OOP_ITERATE_DEFN); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -70,7 +70,7 @@ inline void ParScanClosure::do_oop_work(T* p, bool gc_barrier, bool root_scan) { - assert((!Universe::heap()->is_in_reserved(p) || + assert((!GenCollectedHeap::heap()->is_in_reserved(p) || generation()->is_in_reserved(p)) && (generation()->level() == 0 || gc_barrier), "The gen must be right, and we must be doing the barrier " @@ -82,7 +82,7 @@ #ifndef PRODUCT if (_g->to()->is_in_reserved(obj)) { tty->print_cr("Scanning field (" PTR_FORMAT ") twice?", p2i(p)); - GenCollectedHeap* gch = (GenCollectedHeap*)Universe::heap(); + GenCollectedHeap* gch = GenCollectedHeap::heap(); Space* sp = gch->space_containing(p); oop obj = oop(sp->block_start(p)); assert((HeapWord*)obj < (HeapWord*)p, "Error"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ assert(virtual_space()->is_aligned(gen_size_limit()), "not aligned"); assert(gen_size_limit() >= virtual_space()->committed_size(), "bad gen size"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t result = gen_size_limit() - virtual_space()->committed_size(); size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; @@ -101,7 +101,7 @@ return uncommitted_bytes; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t gen_alignment = heap->generation_alignment(); PSAdaptiveSizePolicy* policy = heap->size_policy(); const size_t working_size = diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ size_t current_committed_size = virtual_space()->committed_size(); assert((gen_size_limit() >= current_committed_size), "generation size limit is wrong"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t result = gen_size_limit() - current_committed_size; size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; @@ -91,7 +91,7 @@ if (eden_space()->is_empty()) { // Respect the minimum size for eden and for the young gen as a whole. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t eden_alignment = heap->space_alignment(); const size_t gen_alignment = heap->generation_alignment(); @@ -128,7 +128,7 @@ // If to_space is below from_space, to_space is not considered. // to_space can be. size_t ASPSYoungGen::available_to_live() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); // Include any space that is committed but is not in eden. @@ -292,7 +292,7 @@ assert(eden_start < from_start, "Cannot push into from_space"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -345,8 +345,6 @@ // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); @@ -509,9 +507,7 @@ assert(from_space()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " @@ -542,7 +538,7 @@ } MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); space_invariants(); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -76,9 +76,7 @@ public: CheckForUnmarkedObjects() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _young_gen = heap->young_gen(); _card_table = barrier_set_cast(heap->barrier_set()); // No point in asserting barrier set type here. Need to make CardTableExtension @@ -325,9 +323,7 @@ void CardTableExtension::verify_all_young_refs_imprecise() { CheckForUnmarkedObjects check; - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); old_gen->object_iterate(&check); @@ -335,9 +331,7 @@ // This should be called immediately after a scavenge, before mutators resume. void CardTableExtension::verify_all_young_refs_precise() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); CheckForPreciseMarks check( @@ -351,7 +345,7 @@ void CardTableExtension::verify_all_young_refs_precise_helper(MemRegion mr) { CardTableExtension* card_table = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(ParallelScavengeHeap::heap()->barrier_set()); jbyte* bot = card_table->byte_for(mr.start()); jbyte* top = card_table->byte_for(mr.end()); @@ -523,7 +517,7 @@ cur_committed = new_committed; } #ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); assert(cur_committed.start() == (HeapWord*) align_size_up((uintptr_t) cur_committed.start(), os::vm_page_size()), diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -78,13 +78,7 @@ CardTableExtension* const barrier_set = new CardTableExtension(reserved_region()); barrier_set->initialize(); - _barrier_set = barrier_set; - oopDesc::set_bs(_barrier_set); - if (_barrier_set == NULL) { - vm_shutdown_during_initialization( - "Could not reserve enough space for barrier set"); - return JNI_ENOMEM; - } + set_barrier_set(barrier_set); // Make up the generations // Calculate the maximum size that a generation can grow. This @@ -95,6 +89,7 @@ double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; + _psh = this; _gens = new AdjoiningGenerations(heap_rs, _collector_policy, generation_alignment()); _old_gen = _gens->old_gen(); @@ -120,7 +115,6 @@ // initialize the policy counters - 2 collectors, 3 generations _gc_policy_counters = new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 3, _size_policy); - _psh = this; // Set up the GCTaskManager _gc_task_manager = GCTaskManager::create(ParallelGCThreads); @@ -176,27 +170,11 @@ } bool ParallelScavengeHeap::is_in(const void* p) const { - if (young_gen()->is_in(p)) { - return true; - } - - if (old_gen()->is_in(p)) { - return true; - } - - return false; + return young_gen()->is_in(p) || old_gen()->is_in(p); } bool ParallelScavengeHeap::is_in_reserved(const void* p) const { - if (young_gen()->is_in_reserved(p)) { - return true; - } - - if (old_gen()->is_in_reserved(p)) { - return true; - } - - return false; + return young_gen()->is_in_reserved(p) || old_gen()->is_in_reserved(p); } bool ParallelScavengeHeap::is_scavengable(const void* addr) { @@ -265,7 +243,7 @@ // total_collections() value! { MutexLocker ml(Heap_lock); - gc_count = Universe::heap()->total_collections(); + gc_count = total_collections(); result = young_gen()->allocate(size); if (result != NULL) { @@ -315,8 +293,7 @@ // This prevents us from looping until time out on requests that can // not be satisfied. if (op.prologue_succeeded()) { - assert(Universe::heap()->is_in_or_null(op.result()), - "result not in heap"); + assert(is_in_or_null(op.result()), "result not in heap"); // If GC was locked out during VM operation then retry allocation // and/or stall as necessary. @@ -426,7 +403,7 @@ HeapWord* ParallelScavengeHeap::failed_mem_allocate(size_t size) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!is_gc_active(), "not reentrant"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); // We assume that allocation in eden will fail unless we collect. @@ -514,18 +491,14 @@ { MutexLocker ml(Heap_lock); // This value is guarded by the Heap_lock - gc_count = Universe::heap()->total_collections(); - full_gc_count = Universe::heap()->total_full_collections(); + gc_count = total_collections(); + full_gc_count = total_full_collections(); } VM_ParallelGCSystemGC op(gc_count, full_gc_count, cause); VMThread::execute(&op); } -void ParallelScavengeHeap::oop_iterate(ExtendedOopClosure* cl) { - Unimplemented(); -} - void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { young_gen()->object_iterate(cl); old_gen()->object_iterate(cl); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -32,8 +32,9 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" #include "gc_implementation/shared/gcWhen.hpp" -#include "gc_interface/collectedHeap.inline.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" +#include "memory/strongRootsScope.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; @@ -131,9 +132,6 @@ // the young gen. virtual bool is_scavengable(const void* addr); - // Does this heap support heap inspection? (+PrintClassHistogram) - bool supports_heap_inspection() const { return true; } - size_t max_capacity() const; // Whether p is in the allocated part of the heap @@ -201,7 +199,6 @@ // initializing stores to an object at this address. virtual bool can_elide_initializing_store_barrier(oop new_obj); - void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); } @@ -238,7 +235,7 @@ void gen_mangle_unused_area() PRODUCT_RETURN; // Call these in sequential code around the processing of strong roots. - class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope { + class ParStrongRootsScope : public MarkScope { public: ParStrongRootsScope(); ~ParStrongRootsScope(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -41,13 +41,14 @@ #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" #include "services/management.hpp" +#include "utilities/stack.inline.hpp" // // ThreadRootsMarkingTask // void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); ResourceMark rm; @@ -78,7 +79,7 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -149,7 +150,7 @@ void RefProcTaskProxy::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("RefProcTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -167,7 +168,7 @@ void RefProcTaskExecutor::execute(ProcessTask& task) { - ParallelScavengeHeap* heap = PSParallelCompact::gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); RegionTaskQueueSet* qset = ParCompactionManager::region_array(); @@ -188,7 +189,7 @@ void RefProcTaskExecutor::execute(EnqueueTask& task) { - ParallelScavengeHeap* heap = PSParallelCompact::gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); GCTaskQueue* q = GCTaskQueue::create(); for(uint i=0; iis_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -237,7 +238,7 @@ _terminator(t) {} void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -319,7 +320,7 @@ } void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -30,7 +30,10 @@ #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -57,8 +60,7 @@ _region_stack(NULL), _region_stack_index((uint)max_uintx) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _start_array = old_gen()->start_array(); @@ -174,6 +176,142 @@ return _manager_array[index]; } +void InstanceKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + assert(obj != NULL, "can't follow the content of NULL object"); + + PSParallelCompact::follow_klass(cm, this); + // Only mark the header and let the scan of the meta-data mark + // everything else. + + PSParallelCompact::MarkAndPushClosure cl(cm); + InstanceKlass::oop_oop_iterate_oop_maps(obj, &cl); +} + +void InstanceMirrorKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + InstanceKlass::oop_pc_follow_contents(obj, cm); + + // Follow the klass field in the mirror. + Klass* klass = java_lang_Class::as_Klass(obj); + if (klass != NULL) { + // An anonymous class doesn't have its own class loader, so the call + // to follow_klass will mark and push its java mirror instead of the + // class loader. When handling the java mirror for an anonymous class + // we need to make sure its class loader data is claimed, this is done + // by calling follow_class_loader explicitly. For non-anonymous classes + // the call to follow_class_loader is made when the class loader itself + // is handled. + if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { + PSParallelCompact::follow_class_loader(cm, klass->class_loader_data()); + } else { + PSParallelCompact::follow_klass(cm, klass); + } + } else { + // If klass is NULL then this a mirror for a primitive type. + // We don't have to follow them, since they are handled as strong + // roots in Universe::oops_do. + assert(java_lang_Class::is_primitive(obj), "Sanity check"); + } + + PSParallelCompact::MarkAndPushClosure cl(cm); + oop_oop_iterate_statics(obj, &cl); +} + +void InstanceClassLoaderKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + InstanceKlass::oop_pc_follow_contents(obj, cm); + + ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); + if (loader_data != NULL) { + PSParallelCompact::follow_class_loader(cm, loader_data); + } +} + +template +static void oop_pc_follow_contents_specialized(InstanceRefKlass* klass, oop obj, ParCompactionManager* cm) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("InstanceRefKlass::oop_pc_follow_contents " PTR_FORMAT, p2i(obj)); + } + ) + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && + PSParallelCompact::ref_processor()->discover_reference(obj, klass->reference_type())) { + // reference already enqueued, referent will be traversed later + klass->InstanceKlass::oop_pc_follow_contents(obj, cm); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); + } + ) + return; + } else { + // treat referent as normal oop + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL normal " PTR_FORMAT, p2i(obj)); + } + ) + PSParallelCompact::mark_and_push(cm, referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + PSParallelCompact::mark_and_push(cm, discovered_addr); + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + T next = oopDesc::load_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + PSParallelCompact::mark_and_push(cm, next_addr); + klass->InstanceKlass::oop_pc_follow_contents(obj, cm); +} + + +void InstanceRefKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(this, obj, cm); + } else { + oop_pc_follow_contents_specialized(this, obj, cm); + } +} + +void ObjArrayKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + PSParallelCompact::follow_klass(cm, this); + + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(objArrayOop(obj), 0, cm); + } else { + oop_pc_follow_contents_specialized(objArrayOop(obj), 0, cm); + } +} + +void TypeArrayKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + assert(obj->is_typeArray(),"must be a type array"); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. +} + void ParCompactionManager::follow_marking_stacks() { do { // Drain the overflow stack first, to allow stealing from the marking stack. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,9 +26,11 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSCOMPACTIONMANAGER_INLINE_HPP #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "oops/objArrayKlass.inline.hpp" -#include "oops/oop.pcgc.inline.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" +#include "oops/objArrayOop.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" void ParCompactionManager::push_objarray(oop obj, size_t index) { @@ -49,16 +51,42 @@ } inline void ParCompactionManager::follow_contents(oop obj) { - obj->follow_contents(this); + assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); + obj->pc_follow_contents(this); +} + +template +inline void oop_pc_follow_contents_specialized(objArrayOop obj, int index, ParCompactionManager* cm) { + const size_t len = size_t(obj->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)obj->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + PSParallelCompact::mark_and_push(cm, e); + } + + if (end_index < len) { + cm->push_objarray(obj, end_index); // Push the continuation. + } } inline void ParCompactionManager::follow_contents(objArrayOop obj, int index) { - ObjArrayKlass* k = (ObjArrayKlass*)obj->klass(); - k->oop_follow_contents(this, obj, index); + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(obj, index, this); + } else { + oop_pc_follow_contents_specialized(obj, index, this); + } } inline void ParCompactionManager::update_contents(oop obj) { - obj->update_contents(this); + obj->pc_update_contents(); } #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSCOMPACTIONMANAGER_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -59,7 +59,7 @@ CollectorCounters* PSMarkSweep::_counters = NULL; void PSMarkSweep::initialize() { - MemRegion mr = Universe::heap()->reserved_region(); + MemRegion mr = ParallelScavengeHeap::heap()->reserved_region(); _ref_processor = new ReferenceProcessor(mr); // a vanilla ref proc _counters = new CollectorCounters("PSMarkSweep", 1); } @@ -81,9 +81,9 @@ void PSMarkSweep::invoke(bool maximum_heap_compaction) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!ParallelScavengeHeap::heap()->is_gc_active(), "not reentrant"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); PSAdaptiveSizePolicy* policy = heap->size_policy(); IsGCActiveMark mark; @@ -110,8 +110,7 @@ return false; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); _gc_timer->register_gc_start(); @@ -487,9 +486,7 @@ } void PSMarkSweep::allocate_stacks() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); MutableSpace* to_space = young_gen->to_space(); @@ -515,8 +512,7 @@ GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); trace(" 1"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Need to clear claim bits before the tracing starts. ClassLoaderDataGraph::clear_claimed_marks(); @@ -582,9 +578,7 @@ // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); // Begin compacting into the old gen @@ -606,9 +600,7 @@ GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); trace("3"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); @@ -651,9 +643,7 @@ // All pointers are now adjusted, move objects accordingly - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -38,15 +38,12 @@ void PSMarkSweepDecorator::set_destination_decorator_tenured() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _destination_decorator = heap->old_gen()->object_mark_sweep(); } void PSMarkSweepDecorator::advance_destination_decorator() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); assert(_destination_decorator != NULL, "Sanity"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -107,20 +107,22 @@ SpaceMangler::mangle_region(cmr); } - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + BarrierSet* bs = heap->barrier_set(); - CardTableModRefBS* _ct = - barrier_set_cast(Universe::heap()->barrier_set()); + bs->resize_covered_region(cmr); + + CardTableModRefBS* ct = barrier_set_cast(bs); // Verify that the start and end of this generation is the start of a card. // If this wasn't true, a single card could span more than one generation, // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. - guarantee(_ct->is_card_aligned(_reserved.start()), "generation must be card aligned"); - if (_reserved.end() != Universe::heap()->reserved_region().end()) { + guarantee(ct->is_card_aligned(_reserved.start()), "generation must be card aligned"); + if (_reserved.end() != heap->reserved_region().end()) { // Don't check at the very end of the heap as we'll assert that we're probing off // the end if we try. - guarantee(_ct->is_card_aligned(_reserved.end()), "generation must be card aligned"); + guarantee(ct->is_card_aligned(_reserved.end()), "generation must be card aligned"); } // @@ -161,8 +163,7 @@ } void PSOldGen::precompact() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Reset start array first. start_array()->reset(); @@ -197,7 +198,7 @@ // Allocations in the old generation need to be reported if (res != NULL) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); heap->size_policy()->tenured_allocation(word_size); } @@ -376,8 +377,7 @@ } if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print_cr("AdaptiveSizePolicy::old generation size: " "collection: %d " "(" SIZE_FORMAT ") -> (" SIZE_FORMAT ") ", @@ -397,7 +397,7 @@ size_t new_word_size = new_memregion.word_size(); start_array()->set_covered_region(new_memregion); - Universe::heap()->barrier_set()->resize_covered_region(new_memregion); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(new_memregion); // ALWAYS do this last!! object_space()->initialize(new_memregion, diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -34,7 +34,7 @@ #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" #include "gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.hpp" @@ -48,7 +48,10 @@ #include "memory/gcLocker.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/referenceProcessor.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/fprofiler.hpp" @@ -745,7 +748,7 @@ HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr) { assert(addr != NULL, "Should detect NULL oop earlier"); - assert(PSParallelCompact::gc_heap()->is_in(addr), "not in heap"); + assert(ParallelScavengeHeap::heap()->is_in(addr), "not in heap"); assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked"); // Region covering the object. @@ -823,16 +826,8 @@ PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure; PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure; -void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } -void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } - void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); } -void PSParallelCompact::MarkAndPushClosure::do_oop(oop* p) { - mark_and_push(_compaction_manager, p); -} -void PSParallelCompact::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(_compaction_manager, p); } - void PSParallelCompact::FollowKlassClosure::do_klass(Klass* klass) { klass->oops_do(_mark_and_push_closure); } @@ -841,9 +836,7 @@ } void PSParallelCompact::post_initialize() { - ParallelScavengeHeap* heap = gc_heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MemRegion mr = heap->reserved_region(); _ref_processor = new ReferenceProcessor(mr, // span @@ -860,8 +853,7 @@ } bool PSParallelCompact::initialize() { - ParallelScavengeHeap* heap = gc_heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MemRegion mr = heap->reserved_region(); // Was the old gen get allocated successfully? @@ -895,7 +887,7 @@ { memset(&_space_info, 0, sizeof(_space_info)); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); _space_info[old_space_id].set_space(heap->old_gen()->object_space()); @@ -978,7 +970,7 @@ // promotion failure does not swap spaces) because an unknown number of minor // collections will have swapped the spaces an unknown number of times. GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -1033,7 +1025,7 @@ MutableSpace* const from_space = _space_info[from_space_id].space(); MutableSpace* const to_space = _space_info[to_space_id].space(); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); bool eden_empty = eden_space->is_empty(); if (!eden_empty) { eden_empty = absorb_live_data_from_eden(heap->size_policy(), @@ -1971,7 +1963,7 @@ assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); assert(!heap->is_gc_active(), "not reentrant"); @@ -1999,7 +1991,7 @@ return false; } - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _gc_timer.register_gc_start(); _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); @@ -2352,7 +2344,7 @@ // Recursively traverse all live objects and mark them GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); TaskQueueSetSuper* qset = ParCompactionManager::region_array(); @@ -2692,8 +2684,7 @@ // trace("5"); GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); old_gen->start_array()->reset(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2844,7 +2835,7 @@ // heap, last_space_id is returned. In debug mode it expects the address to be // in the heap and asserts such. PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) { - assert(Universe::heap()->is_in_reserved(addr), "addr not in the heap"); + assert(ParallelScavengeHeap::heap()->is_in_reserved(addr), "addr not in the heap"); for (unsigned int id = old_space_id; id < last_space_id; ++id) { if (_space_info[id].space()->contains(addr)) { @@ -3338,6 +3329,71 @@ update_state(words); } +void InstanceKlass::oop_pc_update_pointers(oop obj) { + oop_oop_iterate_oop_maps(obj, PSParallelCompact::adjust_pointer_closure()); +} + +void InstanceMirrorKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); + + oop_oop_iterate_statics(obj, PSParallelCompact::adjust_pointer_closure()); +} + +void InstanceClassLoaderKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); +} + +#ifdef ASSERT +template static void trace_reference_gc(const char *s, oop obj, + T* referent_addr, + T* next_addr, + T* discovered_addr) { + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); + gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(referent_addr), + referent_addr ? p2i(oopDesc::load_decode_heap_oop(referent_addr)) : NULL); + gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(next_addr), + next_addr ? p2i(oopDesc::load_decode_heap_oop(next_addr)) : NULL); + gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(discovered_addr), + discovered_addr ? p2i(oopDesc::load_decode_heap_oop(discovered_addr)) : NULL); + } +} +#endif + +template +static void oop_pc_update_pointers_specialized(oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + PSParallelCompact::adjust_pointer(referent_addr); + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + PSParallelCompact::adjust_pointer(next_addr); + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + PSParallelCompact::adjust_pointer(discovered_addr); + debug_only(trace_reference_gc("InstanceRefKlass::oop_update_ptrs", obj, + referent_addr, next_addr, discovered_addr);) +} + +void InstanceRefKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); + + if (UseCompressedOops) { + oop_pc_update_pointers_specialized(obj); + } else { + oop_pc_update_pointers_specialized(obj); + } +} + +void ObjArrayKlass::oop_pc_update_pointers(oop obj) { + assert(obj->is_objArray(), "obj must be obj array"); + oop_oop_iterate_elements(objArrayOop(obj), PSParallelCompact::adjust_pointer_closure()); +} + +void TypeArrayKlass::oop_pc_update_pointers(oop obj) { + assert(obj->is_typeArray(),"must be a type array"); +} + ParMarkBitMapClosure::IterationStatus MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != NULL, "sanity"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,11 +26,12 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_HPP #include "gc_implementation/parallelScavenge/objectStartArray.hpp" +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/parMarkBitMap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" #include "gc_implementation/shared/collectorCounters.hpp" #include "gc_implementation/shared/mutableSpace.hpp" -#include "memory/sharedHeap.hpp" +#include "gc_interface/collectedHeap.hpp" #include "oops/oop.hpp" class ParallelScavengeHeap; @@ -951,12 +952,14 @@ virtual void do_void(); }; - class AdjustPointerClosure: public OopClosure { + class AdjustPointerClosure: public ExtendedOopClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - // do not walk from thread stacks to the code cache on this phase - virtual void do_code_blob(CodeBlob* cb) const { } + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; class AdjustKlassClosure : public KlassClosure { @@ -1139,13 +1142,18 @@ static void reset_millis_since_last_gc(); public: - class MarkAndPushClosure: public OopClosure { + class MarkAndPushClosure: public ExtendedOopClosure { private: ParCompactionManager* _compaction_manager; public: MarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } + + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; // The one and only place to start following the classes. @@ -1161,11 +1169,6 @@ PSParallelCompact(); - // Convenient accessor for Universe::heap(). - static ParallelScavengeHeap* gc_heap() { - return (ParallelScavengeHeap*)Universe::heap(); - } - static void invoke(bool maximum_heap_compaction); static bool invoke_no_policy(bool maximum_heap_compaction); @@ -1177,7 +1180,9 @@ static bool initialize(); // Closure accessors - static OopClosure* adjust_pointer_closure() { return (OopClosure*)&_adjust_pointer_closure; } + static PSParallelCompact::AdjustPointerClosure* adjust_pointer_closure() { + return &_adjust_pointer_closure; + } static KlassClosure* adjust_klass_closure() { return (KlassClosure*)&_adjust_klass_closure; } static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&_is_alive_closure; } @@ -1333,39 +1338,6 @@ } template -inline void PSParallelCompact::mark_and_push(ParCompactionManager* cm, T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (mark_bitmap()->is_unmarked(obj) && mark_obj(obj)) { - cm->push(obj); - } - } -} - -template -inline void PSParallelCompact::adjust_pointer(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - oop new_obj = (oop)summary_data().calc_new_pointer(obj); - assert(new_obj != NULL, // is forwarding ptr? - "should be forwarded"); - // Just always do the update unconditionally? - if (new_obj != NULL) { - assert(Universe::heap()->is_in_reserved(new_obj), - "should be in object space"); - oopDesc::encode_store_heap_oop_not_null(p, new_obj); - } - } -} - -inline void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { - oop holder = klass->klass_holder(); - PSParallelCompact::mark_and_push(cm, &holder); -} - -template inline void PSParallelCompact::KeepAliveClosure::do_oop_work(T* p) { mark_and_push(_compaction_manager, p); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP + +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" +#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_interface/collectedHeap.hpp" +#include "oops/klass.hpp" +#include "oops/oop.inline.hpp" + +template +inline void PSParallelCompact::mark_and_push(ParCompactionManager* cm, T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); + + if (mark_bitmap()->is_unmarked(obj) && mark_obj(obj)) { + cm->push(obj); + } + } +} + +template +inline void PSParallelCompact::MarkAndPushClosure::do_oop_nv(T* p) { + mark_and_push(_compaction_manager, p); +} + +inline void PSParallelCompact::MarkAndPushClosure::do_oop(oop* p) { do_oop_nv(p); } +inline void PSParallelCompact::MarkAndPushClosure::do_oop(narrowOop* p) { do_oop_nv(p); } + +inline void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { + oop holder = klass->klass_holder(); + mark_and_push(cm, &holder); +} + +template +inline void PSParallelCompact::adjust_pointer(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); + + oop new_obj = (oop)summary_data().calc_new_pointer(obj); + assert(new_obj != NULL, // is forwarding ptr? + "should be forwarded"); + // Just always do the update unconditionally? + if (new_obj != NULL) { + assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), + "should be in object space"); + oopDesc::encode_store_heap_oop_not_null(p, new_obj); + } + } +} + +template +void PSParallelCompact::AdjustPointerClosure::do_oop_nv(T* p) { + adjust_pointer(p); +} + +inline void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { do_oop_nv(p); } +inline void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { do_oop_nv(p); } + +#endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ } bool PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { - assert(Universe::heap()->is_in(obj), "Object outside heap"); + assert(ParallelScavengeHeap::heap()->is_in(obj), "Object outside heap"); if (contains(obj)) { HeapWord* object_end = obj + obj_size; @@ -137,9 +137,7 @@ #ifdef ASSERT bool PSYoungPromotionLAB::lab_is_valid(MemRegion lab) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MutableSpace* to_space = heap->young_gen()->to_space(); MemRegion used = to_space->used_region(); if (used.contains(lab)) { @@ -150,10 +148,9 @@ } bool PSOldPromotionLAB::lab_is_valid(MemRegion lab) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); assert(_start_array->covered_region().contains(lab), "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); MemRegion used = old_gen->object_space()->used_region(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_HPP #include "gc_implementation/parallelScavenge/objectStartArray.hpp" -#include "gc_interface/collectedHeap.inline.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.hpp" // @@ -59,7 +59,7 @@ // The shared initialize code invokes this. debug_only(virtual bool lab_is_valid(MemRegion lab) { return false; }); - PSPromotionLAB() : _top(NULL), _bottom(NULL), _end(NULL) { } + PSPromotionLAB() : _top(NULL), _bottom(NULL), _end(NULL), _state(zero_size) { } public: // Filling and flushing. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -32,6 +32,9 @@ #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "memory/padded.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/stack.inline.hpp" @@ -41,8 +44,7 @@ MutableSpace* PSPromotionManager::_young_space = NULL; void PSPromotionManager::initialize() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _young_space = heap->young_gen()->to_space(); @@ -85,8 +87,7 @@ } void PSPromotionManager::pre_scavenge() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _young_space = heap->young_gen()->to_space(); @@ -129,7 +130,7 @@ void PSPromotionManager::print_taskqueue_stats(outputStream* const out) { out->print_cr("== GC Tasks Stats, GC %3d", - Universe::heap()->total_collections()); + ParallelScavengeHeap::heap()->total_collections()); TaskQueueStats totals; out->print("thr "); TaskQueueStats::print_header(1, out); out->cr(); @@ -157,8 +158,7 @@ #endif // TASKQUEUE_STATS PSPromotionManager::PSPromotionManager() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); @@ -188,8 +188,7 @@ // We need to get an assert in here to make sure the labs are always flushed. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Do not prefill the LAB's, save heap wastage! HeapWord* lab_base = young_space()->top(); @@ -210,8 +209,7 @@ totally_drain = totally_drain || _totally_drain; #ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MutableSpace* to_space = heap->young_gen()->to_space(); MutableSpace* old_space = heap->old_gen()->object_space(); #endif /* ASSERT */ @@ -308,6 +306,118 @@ } } +class PushContentsClosure : public ExtendedOopClosure { + PSPromotionManager* _pm; + public: + PushContentsClosure(PSPromotionManager* pm) : _pm(pm) {} + + template void do_oop_nv(T* p) { + if (PSScavenge::should_scavenge(p)) { + _pm->claim_or_forward_depth(p); + } + } + + virtual void do_oop(oop* p) { do_oop_nv(p); } + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + + // Don't use the oop verification code in the oop_oop_iterate framework. + debug_only(virtual bool should_verify_oops() { return false; }) +}; + +void InstanceKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + PushContentsClosure cl(pm); + oop_oop_iterate_oop_maps_reverse(obj, &cl); +} + +void InstanceMirrorKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + // Note that we don't have to follow the mirror -> klass pointer, since all + // klasses that are dirty will be scavenged when we iterate over the + // ClassLoaderData objects. + + InstanceKlass::oop_ps_push_contents(obj, pm); + + PushContentsClosure cl(pm); + oop_oop_iterate_statics(obj, &cl); +} + +void InstanceClassLoaderKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + InstanceKlass::oop_ps_push_contents(obj, pm); + + // This is called by the young collector. It will already have taken care of + // all class loader data. So, we don't have to follow the class loader -> + // class loader data link. +} + +template +static void oop_ps_push_contents_specialized(oop obj, InstanceRefKlass *klass, PSPromotionManager* pm) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + if (PSScavenge::should_scavenge(referent_addr)) { + ReferenceProcessor* rp = PSScavenge::reference_processor(); + if (rp->discover_reference(obj, klass->reference_type())) { + // reference already enqueued, referent and next will be traversed later + klass->InstanceKlass::oop_ps_push_contents(obj, pm); + return; + } else { + // treat referent as normal oop + pm->claim_or_forward_depth(referent_addr); + } + } + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + if (PSScavenge::should_scavenge(discovered_addr)) { + pm->claim_or_forward_depth(discovered_addr); + } + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + oop next = oopDesc::load_decode_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + + // Treat next as normal oop; next is a link in the reference queue. + if (PSScavenge::should_scavenge(next_addr)) { + pm->claim_or_forward_depth(next_addr); + } + klass->InstanceKlass::oop_ps_push_contents(obj, pm); +} + +void InstanceRefKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + if (UseCompressedOops) { + oop_ps_push_contents_specialized(obj, this, pm); + } else { + oop_ps_push_contents_specialized(obj, this, pm); + } +} + +void ObjArrayKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + assert(obj->is_objArray(), "obj must be obj array"); + PushContentsClosure cl(pm); + oop_oop_iterate_elements(objArrayOop(obj), &cl); +} + +void TypeArrayKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + assert(obj->is_typeArray(),"must be a type array"); + ShouldNotReachHere(); +} + oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { assert(_old_gen_is_full || PromotionFailureALot, "Sanity"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_INLINE_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_INLINE_HPP +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" -#include "oops/oop.psgc.inline.hpp" +#include "oops/oop.inline.hpp" inline PSPromotionManager* PSPromotionManager::manager_array(int index) { assert(_manager_array != NULL, "access of NULL manager_array"); @@ -57,9 +58,7 @@ template inline void PSPromotionManager::claim_or_forward_depth(T* p) { assert(should_scavenge(p, true), "revisiting object?"); - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, - "Sanity"); - assert(Universe::heap()->is_in(p), "pointer outside heap"); + assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap"); claim_or_forward_internal_depth(p); } @@ -92,7 +91,7 @@ } inline void PSPromotionManager::push_contents(oop obj) { - obj->push_contents(this); + obj->ps_push_contents(this); } // // This method is pretty bulky. It would be nice to split it up @@ -150,7 +149,7 @@ // Otherwise try allocating obj tenured if (new_obj == NULL) { #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (ParallelScavengeHeap::heap()->promotion_should_fail()) { return oop_promotion_failed(o, test_mark); } #endif // #ifndef PRODUCT @@ -296,7 +295,7 @@ // that are outside the heap. These pointers are either from roots // or from metadata. if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) && - Universe::heap()->is_in_reserved(p)) { + ParallelScavengeHeap::heap()->is_in_reserved(p)) { if (PSScavenge::is_obj_in_young(new_obj)) { PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -87,8 +87,7 @@ public: PSKeepAliveClosure(PSPromotionManager* pm) : _promotion_manager(pm) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _to_space = heap->young_gen()->to_space(); assert(_promotion_manager != NULL, "Sanity"); @@ -218,11 +217,9 @@ bool PSScavenge::invoke() { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!ParallelScavengeHeap::heap()->is_gc_active(), "not reentrant"); - ParallelScavengeHeap* const heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); PSAdaptiveSizePolicy* policy = heap->size_policy(); IsGCActiveMark mark; @@ -273,9 +270,8 @@ return false; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Check for potential problems. if (!should_attempt_scavenge()) { @@ -713,9 +709,7 @@ // unforwarding markOops. It then restores any preserved mark oops, // and clears the _preserved_mark_stack. void PSScavenge::clean_up_failed_promotion() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); { @@ -742,7 +736,7 @@ } // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(heap->reset_promotion_should_fail();) } // This method is called whenever an attempt to promote an object @@ -761,8 +755,7 @@ } bool PSScavenge::should_attempt_scavenge() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); if (UsePerfData) { @@ -838,9 +831,7 @@ MaxTenuringThreshold; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ #include "utilities/globalDefinitions.hpp" inline void PSScavenge::save_to_space_top_before_gc() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _to_space_top_before_gc = heap->young_gen()->to_space()->top(); } @@ -56,7 +56,7 @@ template inline bool PSScavenge::should_scavenge(T* p, bool check_to_space) { if (check_to_space) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); return should_scavenge(p, heap->young_gen()->to_space()); } return should_scavenge(p); @@ -97,7 +97,6 @@ ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); assert(!psh->is_in_reserved(p), "GC barrier needed"); if (PSScavenge::should_scavenge(p)) { - assert(!Universe::heap()->is_in_reserved(p), "Not from meta-data?"); assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); oop o = *p; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -47,7 +47,7 @@ // void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); PSScavengeRootsClosure roots_closure(pm); @@ -118,7 +118,7 @@ // void ThreadRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); PSScavengeRootsClosure roots_closure(pm); @@ -143,7 +143,7 @@ _terminator(t) {} void StealTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); @@ -181,10 +181,8 @@ { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); - - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); CardTableExtension* card_table = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(ParallelScavengeHeap::heap()->barrier_set()); card_table->scavenge_contents_parallel(_gen->start_array(), _gen->object_space(), diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it @@ -103,7 +103,7 @@ _max_gen_size, _virtual_space); // Compute maximum space sizes for performance counters - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t alignment = heap->space_alignment(); size_t size = virtual_space()->reserved_size(); @@ -153,8 +153,7 @@ } void PSYoungGen::compute_initial_space_boundaries() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Compute sizes size_t alignment = heap->space_alignment(); @@ -208,7 +207,7 @@ #ifndef PRODUCT void PSYoungGen::space_invariants() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); // Currently, our eden size cannot shrink to zero @@ -494,7 +493,7 @@ char* to_start = (char*)to_space()->bottom(); char* to_end = (char*)to_space()->end(); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -546,8 +545,6 @@ // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); @@ -708,9 +705,7 @@ assert(from_space()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " @@ -843,7 +838,7 @@ // from-space. size_t PSYoungGen::available_to_live() { size_t delta_in_survivor = 0; - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t space_alignment = heap->space_alignment(); const size_t gen_alignment = heap->generation_alignment(); @@ -927,7 +922,7 @@ MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); space_invariants(); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -41,8 +41,7 @@ void VM_ParallelGCFailedAllocation::doit() { SvcGCMarker sgcm(SvcGCMarker::MINOR); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "must be a ParallelScavengeHeap"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCauseSetter gccs(heap, _gc_cause); _result = heap->failed_mem_allocate(_word_size); @@ -63,9 +62,7 @@ void VM_ParallelGCSystemGC::doit() { SvcGCMarker sgcm(SvcGCMarker::FULL); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, - "must be a ParallelScavengeHeap"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCauseSetter gccs(heap, _gc_cause); if (_gc_cause == GCCause::_gc_locker || _gc_cause == GCCause::_wb_young_gc diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,9 +25,9 @@ #include "precompiled.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/atomic.inline.hpp" #include "utilities/copy.hpp" @@ -79,7 +79,7 @@ } } -uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { +uint ageTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters) { size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); uint result; @@ -126,9 +126,6 @@ age++; } if (UsePerfData) { - SharedHeap* sh = SharedHeap::heap(); - CollectorPolicy* policy = sh->collector_policy(); - GCPolicyCounters* gc_counters = policy->counters(); gc_counters->tenuring_threshold()->set_value(result); gc_counters->desired_survivor_size()->set_value( desired_survivor_size*oopSize); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -29,6 +29,8 @@ #include "oops/oop.hpp" #include "runtime/perfData.hpp" +class GCPolicyCounters; + /* Copyright (c) 1992-2009 Oracle and/or its affiliates, and Stanford University. See the LICENSE file for license information. */ @@ -69,7 +71,7 @@ void merge_par(ageTable* subTable); // calculate new tenuring threshold based on age information - uint compute_tenuring_threshold(size_t survivor_capacity); + uint compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters); private: PerfVariable* _perf_sizes[table_size]; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -28,6 +28,8 @@ #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" @@ -55,16 +57,183 @@ CLDToOopClosure MarkSweep::follow_cld_closure(&mark_and_push_closure); CLDToOopClosure MarkSweep::adjust_cld_closure(&adjust_pointer_closure); -void MarkSweep::MarkAndPushClosure::do_oop(oop* p) { mark_and_push(p); } -void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(p); } +template +void MarkSweep::MarkAndPushClosure::do_oop_nv(T* p) { mark_and_push(p); } +void MarkSweep::MarkAndPushClosure::do_oop(oop* p) { do_oop_nv(p); } +void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { do_oop_nv(p); } void MarkSweep::follow_class_loader(ClassLoaderData* cld) { MarkSweep::follow_cld_closure.do_cld(cld); } +void InstanceKlass::oop_ms_follow_contents(oop obj) { + assert(obj != NULL, "can't follow the content of NULL object"); + MarkSweep::follow_klass(this); + + oop_oop_iterate_oop_maps(obj, &MarkSweep::mark_and_push_closure); +} + +void InstanceMirrorKlass::oop_ms_follow_contents(oop obj) { + InstanceKlass::oop_ms_follow_contents(obj); + + // Follow the klass field in the mirror + Klass* klass = java_lang_Class::as_Klass(obj); + if (klass != NULL) { + // An anonymous class doesn't have its own class loader, so the call + // to follow_klass will mark and push its java mirror instead of the + // class loader. When handling the java mirror for an anonymous class + // we need to make sure its class loader data is claimed, this is done + // by calling follow_class_loader explicitly. For non-anonymous classes + // the call to follow_class_loader is made when the class loader itself + // is handled. + if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { + MarkSweep::follow_class_loader(klass->class_loader_data()); + } else { + MarkSweep::follow_klass(klass); + } + } else { + // If klass is NULL then this a mirror for a primitive type. + // We don't have to follow them, since they are handled as strong + // roots in Universe::oops_do. + assert(java_lang_Class::is_primitive(obj), "Sanity check"); + } + + oop_oop_iterate_statics(obj, &MarkSweep::mark_and_push_closure); +} + +void InstanceClassLoaderKlass::oop_ms_follow_contents(oop obj) { + InstanceKlass::oop_ms_follow_contents(obj); + + ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); + + // We must NULL check here, since the class loader + // can be found before the loader data has been set up. + if(loader_data != NULL) { + MarkSweep::follow_class_loader(loader_data); + } +} + +template +static void oop_ms_follow_contents_specialized(InstanceRefKlass* klass, oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("InstanceRefKlass::oop_ms_follow_contents_specialized " PTR_FORMAT, p2i(obj)); + } + ) + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (!referent->is_gc_marked() && + MarkSweep::ref_processor()->discover_reference(obj, klass->reference_type())) { + // reference was discovered, referent will be traversed later + klass->InstanceKlass::oop_ms_follow_contents(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); + } + ) + return; + } else { + // treat referent as normal oop + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL normal " PTR_FORMAT, p2i(obj)); + } + ) + MarkSweep::mark_and_push(referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + MarkSweep::mark_and_push(discovered_addr); + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + oop next = oopDesc::load_decode_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + // treat next as normal oop. next is a link in the reference queue. + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process next as normal " PTR_FORMAT, p2i(next_addr)); + } + ) + MarkSweep::mark_and_push(next_addr); + klass->InstanceKlass::oop_ms_follow_contents(obj); +} + +void InstanceRefKlass::oop_ms_follow_contents(oop obj) { + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(this, obj); + } else { + oop_ms_follow_contents_specialized(this, obj); + } +} + +template +static void oop_ms_follow_contents_specialized(oop obj, int index) { + objArrayOop a = objArrayOop(obj); + const size_t len = size_t(a->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)a->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + MarkSweep::mark_and_push(e); + } + + if (end_index < len) { + MarkSweep::push_objarray(a, end_index); // Push the continuation. + } +} + +void ObjArrayKlass::oop_ms_follow_contents(oop obj) { + assert (obj->is_array(), "obj must be array"); + MarkSweep::follow_klass(this); + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(obj, 0); + } else { + oop_ms_follow_contents_specialized(obj, 0); + } +} + +void TypeArrayKlass::oop_ms_follow_contents(oop obj) { + assert(obj->is_typeArray(),"must be a type array"); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. +} + void MarkSweep::follow_array(objArrayOop array, int index) { - ObjArrayKlass* k = (ObjArrayKlass*)array->klass(); - k->oop_follow_contents(array, index); + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(array, index); + } else { + oop_ms_follow_contents_specialized(array, index); + } } void MarkSweep::follow_stack() { @@ -112,8 +281,10 @@ MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure; -void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } -void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } +template +void MarkSweep::AdjustPointerClosure::do_oop_nv(T* p) { adjust_pointer(p); } +void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { do_oop_nv(p); } +void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { do_oop_nv(p); } void MarkSweep::adjust_marks() { assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(), @@ -175,3 +346,84 @@ } #endif + +int InstanceKlass::oop_ms_adjust_pointers(oop obj) { + int size = size_helper(); + oop_oop_iterate_oop_maps(obj, &MarkSweep::adjust_pointer_closure); + return size; +} + +int InstanceMirrorKlass::oop_ms_adjust_pointers(oop obj) { + int size = oop_size(obj); + InstanceKlass::oop_ms_adjust_pointers(obj); + + oop_oop_iterate_statics(obj, &MarkSweep::adjust_pointer_closure); + return size; +} + +int InstanceClassLoaderKlass::oop_ms_adjust_pointers(oop obj) { + return InstanceKlass::oop_ms_adjust_pointers(obj); +} + +#ifdef ASSERT +template static void trace_reference_gc(const char *s, oop obj, + T* referent_addr, + T* next_addr, + T* discovered_addr) { + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); + gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(referent_addr), + p2i(referent_addr ? + (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL)); + gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(next_addr), + p2i(next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL)); + gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(discovered_addr), + p2i(discovered_addr ? + (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL)); + } +} +#endif + +template void static adjust_object_specialized(oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + MarkSweep::adjust_pointer(referent_addr); + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + MarkSweep::adjust_pointer(next_addr); + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + MarkSweep::adjust_pointer(discovered_addr); + debug_only(trace_reference_gc("InstanceRefKlass::oop_ms_adjust_pointers", obj, + referent_addr, next_addr, discovered_addr);) +} + +int InstanceRefKlass::oop_ms_adjust_pointers(oop obj) { + int size = size_helper(); + InstanceKlass::oop_ms_adjust_pointers(obj); + + if (UseCompressedOops) { + adjust_object_specialized(obj); + } else { + adjust_object_specialized(obj); + } + return size; +} + +int ObjArrayKlass::oop_ms_adjust_pointers(oop obj) { + assert(obj->is_objArray(), "obj must be obj array"); + objArrayOop a = objArrayOop(obj); + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call. + int size = a->object_size(); + oop_oop_iterate_elements(a, &MarkSweep::adjust_pointer_closure); + return size; +} + +int TypeArrayKlass::oop_ms_adjust_pointers(oop obj) { + assert(obj->is_typeArray(), "must be a type array"); + typeArrayOop t = typeArrayOop(obj); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. + return t->object_size(); +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -60,8 +60,9 @@ virtual void do_oop(narrowOop* p); }; - class MarkAndPushClosure: public OopClosure { + class MarkAndPushClosure: public ExtendedOopClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); }; @@ -73,8 +74,12 @@ class AdjustPointerClosure: public OopsInGenClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; // Used for java/lang/ref handling diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -28,11 +28,15 @@ #include "gc_implementation/shared/markSweep.hpp" #include "gc_interface/collectedHeap.hpp" #include "oops/markOop.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/instanceRefKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "utilities/stack.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1StringDedup.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { @@ -59,7 +63,9 @@ } inline void MarkSweep::follow_object(oop obj) { - obj->follow_contents(); + assert(obj->is_gc_marked(), "should be marked"); + + obj->ms_follow_contents(); } template inline void MarkSweep::follow_root(T* p) { @@ -95,13 +101,15 @@ } inline int MarkSweep::adjust_pointers(oop obj) { - return obj->adjust_pointers(); + return obj->ms_adjust_pointers(); } template inline void MarkSweep::adjust_pointer(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in(obj), "should be in heap"); + oop new_obj = oop(obj->mark()->decode_pointer()); assert(new_obj != NULL || // is forwarding ptr? obj->mark() == markOopDesc::prototype() || // not gc marked? diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,7 +26,7 @@ #include "precompiled.hpp" #include "gc_implementation/shared/mutableNUMASpace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" -#include "memory/sharedHeap.hpp" +#include "gc_interface/collectedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/thread.inline.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -116,8 +116,6 @@ _prologue_succeeded = false; } else { _prologue_succeeded = true; - SharedHeap* sh = SharedHeap::heap(); - if (sh != NULL) sh->_thread_holds_heap_lock_for_gc = true; } return _prologue_succeeded; } @@ -126,22 +124,11 @@ void VM_GC_Operation::doit_epilogue() { assert(Thread::current()->is_Java_thread(), "just checking"); // Release the Heap_lock first. - SharedHeap* sh = SharedHeap::heap(); - if (sh != NULL) sh->_thread_holds_heap_lock_for_gc = false; Heap_lock->unlock(); release_and_notify_pending_list_lock(); } -bool VM_GC_HeapInspection::doit_prologue() { - if (Universe::heap()->supports_heap_inspection()) { - return VM_GC_Operation::doit_prologue(); - } else { - return false; - } -} - bool VM_GC_HeapInspection::skip_operation() const { - assert(Universe::heap()->supports_heap_inspection(), "huh?"); return false; } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -150,7 +150,6 @@ ~VM_GC_HeapInspection() {} virtual VMOp_Type type() const { return VMOp_GC_HeapInspection; } virtual bool skip_operation() const; - virtual bool doit_prologue(); virtual void doit(); void set_csv_format(bool value) {_csv_format = value;} void set_print_help(bool value) {_print_help = value;} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_interface/collectedHeap.cpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -220,6 +220,11 @@ } } +void CollectedHeap::set_barrier_set(BarrierSet* barrier_set) { + _barrier_set = barrier_set; + oopDesc::set_bs(_barrier_set); +} + void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_interface/collectedHeap.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -75,9 +75,8 @@ // // CollectedHeap -// SharedHeap -// GenCollectedHeap -// G1CollectedHeap +// GenCollectedHeap +// G1CollectedHeap // ParallelScavengeHeap // class CollectedHeap : public CHeapObj { @@ -205,7 +204,7 @@ // In many heaps, there will be a need to perform some initialization activities // after the Universe is fully formed, but before general heap allocation is allowed. // This is the correct place to place such initialization methods. - virtual void post_initialize() = 0; + virtual void post_initialize(); // Stop any onging concurrent work and prepare for exit. virtual void stop() {} @@ -240,22 +239,11 @@ } // Returns "TRUE" iff "p" points into the committed areas of the heap. - // Since this method can be expensive in general, we restrict its - // use to assertion checking only. + // This method can be expensive so avoid using it in performance critical + // code. virtual bool is_in(const void* p) const = 0; - bool is_in_or_null(const void* p) const { - return p == NULL || is_in(p); - } - - bool is_in_place(Metadata** p) { - return !Universe::heap()->is_in(p); - } - bool is_in_place(oop* p) { return Universe::heap()->is_in(p); } - bool is_in_place(narrowOop* p) { - oop o = oopDesc::load_decode_heap_oop_not_null(p); - return Universe::heap()->is_in((const void*)o); - } + DEBUG_ONLY(bool is_in_or_null(const void* p) const { return p == NULL || is_in(p); }) // Let's define some terms: a "closed" subset of a heap is one that // @@ -451,9 +439,6 @@ // remembered set. virtual void flush_deferred_store_barrier(JavaThread* thread); - // Does this heap support heap inspection (+PrintClassHistogram?) - virtual bool supports_heap_inspection() const = 0; - // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the // "CollectedHeap" supports. @@ -470,6 +455,7 @@ // Returns the barrier set for this heap BarrierSet* barrier_set() { return _barrier_set; } + void set_barrier_set(BarrierSet* barrier_set); // Returns "true" iff there is a stop-world GC in progress. (I assume // that it should answer "false" for the concurrent part of a concurrent @@ -497,12 +483,6 @@ // Return the CollectorPolicy for the heap virtual CollectorPolicy* collector_policy() const = 0; - void oop_iterate_no_header(OopClosure* cl); - - // Iterate over all the ref-containing fields of all objects, calling - // "cl.do_oop" on each. - virtual void oop_iterate(ExtendedOopClosure* cl) = 0; - // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl) = 0; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -236,12 +236,6 @@ return (oop)obj; } -inline void CollectedHeap::oop_iterate_no_header(OopClosure* cl) { - NoHeaderExtendedOopClosure no_header_cl(cl); - oop_iterate(&no_header_cl); -} - - inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, HeapWord* end, unsigned short alignment_in_bytes) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1406,10 +1406,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1422,10 +1423,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1453,10 +1455,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_static_call(info, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_static_call(info, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1464,11 +1467,15 @@ return info.selected_method(); } -methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { +methodHandle LinkResolver::resolve_special_call_or_null( + KlassHandle resolved_klass, + Symbol* name, + Symbol* signature, + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, resolved_klass, name, signature, current_klass, true, THREAD); + resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -181,10 +181,10 @@ // same as above for compile-time resolution; but returns null handle instead of throwing an exception on error // also, does not initialize klass (i.e., no side effects) - static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); + static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method); // same as above for compile-time resolution; returns vtable_index if current_klass if linked diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/cardGeneration.cpp --- a/hotspot/src/share/vm/memory/cardGeneration.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/cardGeneration.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); - if (reserved_mr.end() != Universe::heap()->reserved_region().end()) { + if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { // Don't check at the very end of the heap as we'll assert that we're probing off // the end if we try. guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); @@ -78,7 +78,7 @@ heap_word_size(_virtual_space.committed_size()); MemRegion mr(space()->bottom(), new_word_size); // Expand card table - Universe::heap()->barrier_set()->resize_covered_region(mr); + GenCollectedHeap::heap()->barrier_set()->resize_covered_region(mr); // Expand shared block offset array _bts->resize(new_word_size); @@ -170,7 +170,7 @@ _bts->resize(new_word_size); MemRegion mr(space()->bottom(), new_word_size); // Shrink the card table - Universe::heap()->barrier_set()->resize_covered_region(mr); + GenCollectedHeap::heap()->barrier_set()->resize_covered_region(mr); if (Verbose && PrintGC) { size_t new_mem_size = _virtual_space.committed_size(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" #include "memory/cardTableModRefBS.inline.hpp" #include "memory/cardTableRS.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/space.hpp" #include "memory/space.inline.hpp" #include "memory/universe.hpp" @@ -450,21 +451,20 @@ // This is an example of where n_par_threads() is used instead // of workers()->active_workers(). n_par_threads can be set to 0 to // turn off parallelism. For example when this code is called as - // part of verification and SharedHeap::process_roots() is being - // used, then n_par_threads() may have been set to 0. active_workers - // is not overloaded with the meaning that it is a switch to disable - // parallelism and so keeps the meaning of the number of - // active gc workers. If parallelism has not been shut off by - // setting n_par_threads to 0, then n_par_threads should be - // equal to active_workers. When a different mechanism for shutting - // off parallelism is used, then active_workers can be used in + // part of verification during root processing then n_par_threads() + // may have been set to 0. active_workers is not overloaded with + // the meaning that it is a switch to disable parallelism and so keeps + // the meaning of the number of active gc workers. If parallelism has + // not been shut off by setting n_par_threads to 0, then n_par_threads + // should be equal to active_workers. When a different mechanism for + // shutting off parallelism is used, then active_workers can be used in // place of n_par_threads. - int n_threads = SharedHeap::heap()->n_par_threads(); + int n_threads = GenCollectedHeap::heap()->n_par_threads(); bool is_par = n_threads > 0; if (is_par) { #if INCLUDE_ALL_GCS - assert(SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers(), "Mismatch"); + assert(GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch"); non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); #else // INCLUDE_ALL_GCS fatal("Parallel gc not supported here."); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/cardTableRS.cpp --- a/hotspot/src/share/vm/memory/cardTableRS.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/cardTableRS.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,16 +38,18 @@ GenRemSet(), _cur_youngergen_card_val(youngergenP1_card) { - guarantee(Universe::heap()->kind() == CollectedHeap::GenCollectedHeap, "sanity"); _ct_bs = new CardTableModRefBSForCTRS(whole_heap); _ct_bs->initialize(); set_bs(_ct_bs); - _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1, + // max_gens is really GenCollectedHeap::heap()->gen_policy()->number_of_generations() + // (which is always 2, young & old), but GenCollectedHeap has not been initialized yet. + uint max_gens = 2; + _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, max_gens + 1, mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_last_cur_val_in_gen == NULL) { vm_exit_during_initialization("Could not create last_cur_val_in_gen array."); } - for (int i = 0; i < GenCollectedHeap::max_gens + 1; i++) { + for (uint i = 0; i < max_gens + 1; i++) { _last_cur_val_in_gen[i] = clean_card_val(); } _ct_bs->set_CTRS(this); @@ -167,16 +169,20 @@ // Cannot yet substitute active_workers for n_par_threads // in the case where parallelism is being turned off by // setting n_par_threads to 0. - _is_par = (SharedHeap::heap()->n_par_threads() > 0); + _is_par = (GenCollectedHeap::heap()->n_par_threads() > 0); assert(!_is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); + (GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch"); } bool ClearNoncleanCardWrapper::is_word_aligned(jbyte* entry) { return (((intptr_t)entry) & (BytesPerWord-1)) == 0; } +// The regions are visited in *decreasing* address order. +// This order aids with imprecise card marking, where a dirty +// card may cause scanning, and summarization marking, of objects +// that extend onto subsequent cards. void ClearNoncleanCardWrapper::do_MemRegion(MemRegion mr) { assert(mr.word_size() > 0, "Error"); assert(_ct->is_aligned(mr.start()), "mr.start() should be card aligned"); @@ -591,10 +597,6 @@ // At present, we only know how to verify the card table RS for // generational heaps. VerifyCTGenClosure blk(this); - CollectedHeap* ch = Universe::heap(); - - if (ch->kind() == CollectedHeap::GenCollectedHeap) { - GenCollectedHeap::heap()->generation_iterate(&blk, false); - _ct_bs->verify(); - } - } + GenCollectedHeap::heap()->generation_iterate(&blk, false); + _ct_bs->verify(); +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/collectorPolicy.cpp --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -669,7 +669,7 @@ } // Read the gc count while the heap lock is held. - gc_count_before = Universe::heap()->total_collections(); + gc_count_before = gch->total_collections(); } VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/defNewGeneration.cpp --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -48,6 +48,9 @@ #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/parNew/parOopClosures.hpp" +#endif // // DefNewGeneration functions. @@ -190,7 +193,9 @@ { MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + GenCollectedHeap* gch = GenCollectedHeap::heap(); + + gch->barrier_set()->resize_covered_region(cmr); _eden_space = new ContiguousSpace(); _from_space = new ContiguousSpace(); @@ -202,13 +207,13 @@ // Compute the maximum eden and survivor space sizes. These sizes // are computed assuming the entire reserved space is committed. // These values are exported as performance counters. - uintx alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); + uintx alignment = gch->collector_policy()->space_alignment(); uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, alignment); _max_eden_size = size - (2*_max_survivor_size); // allocate the performance counters - GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy(); + GenCollectorPolicy* gcp = (GenCollectorPolicy*)gch->collector_policy(); // Generation counters -- generation 0, 3 subspaces _gen_counters = new GenerationCounters("new", 0, 3, @@ -378,8 +383,7 @@ int next_level = level() + 1; GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(next_level < gch->n_gens(), - "DefNewGeneration cannot be an oldest gen"); + assert(next_level == 1, "DefNewGeneration must be a young gen"); Generation* old_gen = gch->old_gen(); size_t old_size = old_gen->capacity(); @@ -431,7 +435,7 @@ SpaceDecorator::DontMangle); MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + gch->barrier_set()->resize_covered_region(cmr); if (Verbose && PrintGC) { size_t new_size_after = _virtual_space.committed_size(); size_t eden_size_after = eden()->capacity(); @@ -550,8 +554,9 @@ void DefNewGeneration::adjust_desired_tenuring_threshold() { // Set the desired survivor size to half the real survivor space + GCPolicyCounters* gc_counters = GenCollectedHeap::heap()->collector_policy()->counters(); _tenuring_threshold = - age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); + age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize, gc_counters); } void DefNewGeneration::collect(bool full, @@ -688,7 +693,7 @@ gc_tracer.report_promotion_failed(_promotion_failed_info); // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(gch->reset_promotion_should_fail();) } if (PrintGC && !PrintGCDetails) { gch->print_heap_change(gch_prev_used); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/defNewGeneration.inline.hpp --- a/hotspot/src/share/vm/memory/defNewGeneration.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/defNewGeneration.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,9 +25,9 @@ #ifndef SHARE_VM_MEMORY_DEFNEWGENERATION_INLINE_HPP #define SHARE_VM_MEMORY_DEFNEWGENERATION_INLINE_HPP -#include "gc_interface/collectedHeap.hpp" #include "memory/cardTableRS.hpp" #include "memory/defNewGeneration.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/genOopClosures.inline.hpp" #include "memory/space.hpp" @@ -60,7 +60,7 @@ // We could check that p is also in an older generation, but // dirty cards in the youngest gen are never scanned, so the // extra check probably isn't worthwhile. - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->inline_write_ref_field_gc(p, obj); } @@ -84,7 +84,7 @@ // we set a younger_gen card if we have an older->youngest // generation pointer. oop obj = oopDesc::load_decode_heap_oop_not_null(p); - if (((HeapWord*)obj < _boundary) && Universe::heap()->is_in_reserved(p)) { + if (((HeapWord*)obj < _boundary) && GenCollectedHeap::heap()->is_in_reserved(p)) { _rs->inline_write_ref_field_gc(p, obj); } } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/freeList.cpp --- a/hotspot/src/share/vm/memory/freeList.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/freeList.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,10 +23,10 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/freeList.hpp" #include "memory/metachunk.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/vmThread.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/gcLocker.cpp --- a/hotspot/src/share/vm/memory/gcLocker.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/gcLocker.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,9 +23,9 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/thread.inline.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/genCollectedHeap.cpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -39,7 +39,7 @@ #include "memory/genOopClosures.inline.hpp" #include "memory/generationSpec.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/space.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" @@ -50,9 +50,10 @@ #include "runtime/vmThread.hpp" #include "services/management.hpp" #include "services/memoryService.hpp" +#include "utilities/macros.hpp" +#include "utilities/stack.inline.hpp" #include "utilities/vmError.hpp" #include "utilities/workgroup.hpp" -#include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" @@ -78,21 +79,27 @@ }; GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : - SharedHeap(), + CollectedHeap(), _rem_set(NULL), _gen_policy(policy), _process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)), _full_collections_completed(0) { assert(policy != NULL, "Sanity check"); + if (UseConcMarkSweepGC) { + _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); + _workers->initialize_workers(); + } else { + // Serial GC does not use workers. + _workers = NULL; + } } jint GenCollectedHeap::initialize() { CollectedHeap::pre_initialize(); - _n_gens = gen_policy()->number_of_generations(); - assert(_n_gens == 2, "There is no support for more than two generations"); - // While there are no constraints in the GC code that HeapWordSize // be any particular value, there are multiple other areas in the // system which believe this to be true (e.g. oop->object_size in some @@ -166,7 +173,8 @@ } void GenCollectedHeap::post_initialize() { - SharedHeap::post_initialize(); + CollectedHeap::post_initialize(); + ref_processing_init(); GenCollectorPolicy *policy = (GenCollectorPolicy *)collector_policy(); guarantee(policy->is_generation_policy(), "Illegal policy type"); assert((_young_gen->kind() == Generation::DefNew) || @@ -185,7 +193,6 @@ } void GenCollectedHeap::ref_processing_init() { - SharedHeap::ref_processing_init(); _young_gen->ref_processor_init(); _old_gen->ref_processor_init(); } @@ -200,8 +207,7 @@ // Save the "used_region" for generations level and lower. void GenCollectedHeap::save_used_regions(int level) { - assert(level >= 0, "Illegal level parameter"); - assert(level < _n_gens, "Illegal level parameter"); + assert(level == 0 || level == 1, "Illegal level parameter"); if (level == 1) { _old_gen->save_used_region(); } @@ -417,7 +423,6 @@ assert(Heap_lock->is_locked(), "the requesting thread should have the Heap_lock"); guarantee(!is_gc_active(), "collection is not reentrant"); - assert(max_level < n_gens(), "sanity check"); if (GC_locker::check_active_before_gc()) { return; // GC is disabled (e.g. JNI GetXXXCritical operation) @@ -435,7 +440,7 @@ { FlagSetting fl(_is_gc_active, true); - bool complete = full && (max_level == (n_gens()-1)); + bool complete = full && (max_level == 1 /* old */); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later @@ -507,7 +512,7 @@ // Update "complete" boolean wrt what actually transpired -- // for instance, a promotion failure could have led to // a whole heap collection. - complete = complete || (max_level_collected == n_gens() - 1); + complete = complete || (max_level_collected == 1 /* old */); if (complete) { // We did a "major" collection // FIXME: See comment at pre_full_gc_dump call @@ -524,7 +529,7 @@ } // Adjust generation sizes. - if (max_level_collected == 1) { + if (max_level_collected == 1 /* old */) { _old_gen->compute_new_size(); } _young_gen->compute_new_size(); @@ -560,7 +565,8 @@ } void GenCollectedHeap::set_par_threads(uint t) { - SharedHeap::set_par_threads(t); + assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); + CollectedHeap::set_par_threads(t); set_n_termination(t); } @@ -586,7 +592,7 @@ CLDClosure* strong_cld_closure, CLDClosure* weak_cld_closure, CodeBlobClosure* code_roots) { - StrongRootsScope srs(this, activate_scope); + StrongRootsScope srs(activate_scope); // General roots. assert(Threads::thread_claim_parity() != 0, "must have called prologue code"); @@ -606,7 +612,8 @@ // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway CodeBlobClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots; - Threads::possibly_parallel_oops_do(strong_roots, roots_from_clds_p, roots_from_code_p); + bool is_par = n_par_threads() > 0; + Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_clds_p, roots_from_code_p); if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) { Universe::oops_do(strong_roots); @@ -771,19 +778,19 @@ #endif // INCLUDE_ALL_GCS } else if (cause == GCCause::_wb_young_gc) { // minor collection for WhiteBox API - collect(cause, 0); + collect(cause, 0 /* young */); } else { #ifdef ASSERT if (cause == GCCause::_scavenge_alot) { // minor collection only - collect(cause, 0); + collect(cause, 0 /* young */); } else { // Stop-the-world full collection - collect(cause, n_gens() - 1); + collect(cause, 1 /* old */); } #else // Stop-the-world full collection - collect(cause, n_gens() - 1); + collect(cause, 1 /* old */); #endif } } @@ -798,7 +805,7 @@ void GenCollectedHeap::collect_locked(GCCause::Cause cause) { // The caller has the Heap_lock assert(Heap_lock->owned_by_self(), "this thread should own the Heap_lock"); - collect_locked(cause, n_gens() - 1); + collect_locked(cause, 1 /* old */); } // this is the private collection interface @@ -854,7 +861,7 @@ #endif // INCLUDE_ALL_GCS void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { - do_full_collection(clear_all_soft_refs, _n_gens - 1); + do_full_collection(clear_all_soft_refs, 1 /* old */); } void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, @@ -886,7 +893,7 @@ clear_all_soft_refs /* clear_all_soft_refs */, 0 /* size */, false /* is_tlab */, - n_gens() - 1 /* max_level */); + 1 /* old */ /* max_level */); } } @@ -899,17 +906,6 @@ // Returns "TRUE" iff "p" points into the committed areas of the heap. bool GenCollectedHeap::is_in(const void* p) const { - #ifndef ASSERT - guarantee(VerifyBeforeGC || - VerifyDuringGC || - VerifyBeforeExit || - VerifyDuringStartup || - PrintAssembly || - tty->count() != 0 || // already printing - VerifyAfterGC || - VMError::fatal_error_in_progress(), "too expensive"); - - #endif return _young_gen->is_in(p) || _old_gen->is_in(p); } @@ -923,6 +919,11 @@ } #endif +void GenCollectedHeap::oop_iterate_no_header(OopClosure* cl) { + NoHeaderExtendedOopClosure no_header_cl(cl); + oop_iterate(&no_header_cl); +} + void GenCollectedHeap::oop_iterate(ExtendedOopClosure* cl) { _young_gen->oop_iterate(cl); _old_gen->oop_iterate(cl); @@ -1092,11 +1093,6 @@ } } -void GenCollectedHeap::space_iterate(SpaceClosure* cl) { - _young_gen->space_iterate(cl, true); - _old_gen->space_iterate(cl, true); -} - bool GenCollectedHeap::is_maximal_no_gc() const { return _young_gen->is_maximal_no_gc() && _old_gen->is_maximal_no_gc(); } @@ -1112,9 +1108,7 @@ return _gch; } - void GenCollectedHeap::prepare_for_compaction() { - guarantee(_n_gens = 2, "Wrong number of generations"); // Start by compacting into same gen. CompactPoint cp(_old_gen); _old_gen->prepare_for_compaction(&cp); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/genCollectedHeap.hpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,15 +26,16 @@ #define SHARE_VM_MEMORY_GENCOLLECTEDHEAP_HPP #include "gc_implementation/shared/adaptiveSizePolicy.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" #include "memory/generation.hpp" -#include "memory/sharedHeap.hpp" class SubTasksDone; +class FlexibleWorkGang; -// A "GenCollectedHeap" is a SharedHeap that uses generational +// A "GenCollectedHeap" is a CollectedHeap that uses generational // collection. It has two generations, young and old. -class GenCollectedHeap : public SharedHeap { +class GenCollectedHeap : public CollectedHeap { friend class GenCollectorPolicy; friend class Generation; friend class DefNewGeneration; @@ -51,10 +52,6 @@ friend class GCCauseSetter; friend class VMStructs; public: - enum SomeConstants { - max_gens = 10 - }; - friend class VM_PopulateDumpSharedSpace; protected: @@ -62,8 +59,6 @@ static GenCollectedHeap* _gch; private: - int _n_gens; - Generation* _young_gen; Generation* _old_gen; @@ -93,6 +88,8 @@ // In block contents verification, the number of header words to skip NOT_PRODUCT(static size_t _skip_header_HeapWords;) + FlexibleWorkGang* _workers; + protected: // Helper functions for allocation HeapWord* attempt_allocation(size_t size, @@ -125,6 +122,8 @@ public: GenCollectedHeap(GenCollectorPolicy *policy); + FlexibleWorkGang* workers() const { return _workers; } + GCStats* gc_stats(int level) const; // Returns JNI_OK on success @@ -178,9 +177,6 @@ HeapWord** top_addr() const; HeapWord** end_addr() const; - // Does this heap support heap inspection? (+PrintClassHistogram) - virtual bool supports_heap_inspection() const { return true; } - // Perform a full collection of the heap; intended for use in implementing // "System.gc". This implies as full a collection as the CollectedHeap // supports. Caller does not hold the Heap_lock on entry. @@ -223,6 +219,7 @@ } // Iteration functions. + void oop_iterate_no_header(OopClosure* cl); void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl); @@ -331,7 +328,6 @@ _old_gen->update_gc_stats(current_level, full); } - // Override. bool no_gc_in_progress() { return !is_gc_active(); } // Override. @@ -363,18 +359,11 @@ // If "old_to_young" determines the order. void generation_iterate(GenClosure* cl, bool old_to_young); - void space_iterate(SpaceClosure* cl); - // Return "true" if all generations have reached the // maximal committed limit that they can reach, without a garbage // collection. virtual bool is_maximal_no_gc() const; - int n_gens() const { - assert(_n_gens == gen_policy()->number_of_generations(), "Sanity"); - return _n_gens; - } - // This function returns the "GenRemSet" object that allows us to scan // generations in a fully generational heap. GenRemSet* rem_set() { return _rem_set; } @@ -531,8 +520,8 @@ void record_gen_tops_before_GC() PRODUCT_RETURN; protected: - virtual void gc_prologue(bool full); - virtual void gc_epilogue(bool full); + void gc_prologue(bool full); + void gc_epilogue(bool full); }; #endif // SHARE_VM_MEMORY_GENCOLLECTEDHEAP_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/genOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/genOopClosures.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,30 @@ +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/genOopClosures.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" + +// Generate Serial GC specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/genOopClosures.inline.hpp --- a/hotspot/src/share/vm/memory/genOopClosures.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/genOopClosures.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -31,7 +31,6 @@ #include "memory/genOopClosures.hpp" #include "memory/genRemSet.hpp" #include "memory/generation.hpp" -#include "memory/sharedHeap.hpp" #include "memory/space.hpp" inline OopsInGenClosure::OopsInGenClosure(Generation* gen) : diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/generation.cpp --- a/hotspot/src/share/vm/memory/generation.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/generation.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -187,7 +187,7 @@ assert(obj_size == (size_t)obj->size(), "bad obj_size passed in"); #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/iterator.cpp --- a/hotspot/src/share/vm/memory/iterator.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/iterator.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -23,8 +23,11 @@ */ #include "precompiled.hpp" -#include "memory/iterator.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/universe.hpp" #include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" void KlassToOopClosure::do_klass(Klass* k) { assert(_oop_closure != NULL, "Not initialized?"); @@ -61,19 +64,18 @@ } } -MarkingCodeBlobClosure::MarkScope::MarkScope(bool activate) - : _active(activate) -{ - if (_active) nmethod::oops_do_marking_prologue(); -} - -MarkingCodeBlobClosure::MarkScope::~MarkScope() { - if (_active) nmethod::oops_do_marking_epilogue(); -} - void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { nmethod* nm = cb->as_nmethod_or_null(); if (nm != NULL && !nm->test_set_oops_do_mark()) { do_nmethod(nm); } } + +// Generate the *Klass::oop_oop_iterate functions for the base class +// of the oop closures. These versions use the virtual do_oop calls, +// instead of the devirtualized do_oop_nv version. +ALL_KLASS_OOP_OOP_ITERATE_DEFN(ExtendedOopClosure, _v) + +// Generate the *Klass::oop_oop_iterate functions +// for the NoHeaderExtendedOopClosure helper class. +ALL_KLASS_OOP_OOP_ITERATE_DEFN(NoHeaderExtendedOopClosure, _nv) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/iterator.hpp --- a/hotspot/src/share/vm/memory/iterator.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/iterator.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -44,9 +44,7 @@ class OopClosure : public Closure { public: virtual void do_oop(oop* o) = 0; - virtual void do_oop_v(oop* o) { do_oop(o); } virtual void do_oop(narrowOop* o) = 0; - virtual void do_oop_v(narrowOop* o) { do_oop(o); } }; // ExtendedOopClosure adds extra code to be run during oop iterations. @@ -74,11 +72,9 @@ // Currently, only CMS and G1 need these. virtual bool do_metadata() { return do_metadata_nv(); } - bool do_metadata_v() { return do_metadata(); } bool do_metadata_nv() { return false; } virtual void do_klass(Klass* k) { do_klass_nv(k); } - void do_klass_v(Klass* k) { do_klass(k); } void do_klass_nv(Klass* k) { ShouldNotReachHere(); } virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } @@ -87,6 +83,14 @@ // location without an intervening "major reset" (like the end of a GC). virtual bool idempotent() { return false; } virtual bool apply_to_weak_ref_discovered_field() { return false; } + +#ifdef ASSERT + // Default verification of each visited oop field. + template void verify(T* p); + + // Can be used by subclasses to turn off the default verification of oop fields. + virtual bool should_verify_oops() { return true; } +#endif }; // Wrapper closure only used to implement oop_iterate_no_header(). @@ -147,7 +151,6 @@ }; class CLDToKlassAndOopClosure : public CLDClosure { - friend class SharedHeap; friend class G1CollectedHeap; protected: OopClosure* _oop_closure; @@ -284,16 +287,6 @@ // Called for each code blob, but at most once per unique blob. virtual void do_code_blob(CodeBlob* cb); - - class MarkScope : public StackObj { - protected: - bool _active; - public: - MarkScope(bool activate = true); - // = { if (active) nmethod::oops_do_marking_prologue(); } - ~MarkScope(); - // = { if (active) nmethod::oops_do_marking_epilogue(); } - }; }; // MonitorClosure is used for iterating over monitors in the monitors cache @@ -364,16 +357,33 @@ } }; +// The two class template specializations are used to dispatch calls +// to the ExtendedOopClosure functions. If use_non_virtual_call is true, +// the non-virtual versions are called (E.g. do_oop_nv), otherwise the +// virtual versions are called (E.g. do_oop). -// Helper defines for ExtendOopClosure +template +class Devirtualizer {}; -#define if_do_metadata_checked(closure, nv_suffix) \ - /* Make sure the non-virtual and the virtual versions match. */ \ - assert(closure->do_metadata##nv_suffix() == closure->do_metadata(), \ - "Inconsistency in do_metadata"); \ - if (closure->do_metadata##nv_suffix()) +// Dispatches to the non-virtual functions. +template <> class Devirtualizer { + public: + template static void do_oop(OopClosureType* closure, T* p); + template static void do_klass(OopClosureType* closure, Klass* k); + template static bool do_metadata(OopClosureType* closure); +}; -#define assert_should_ignore_metadata(closure, nv_suffix) \ - assert(!closure->do_metadata##nv_suffix(), "Code to handle metadata is not implemented") +// Dispatches to the virtual functions. +template <> class Devirtualizer { + public: + template static void do_oop(OopClosureType* closure, T* p); + template static void do_klass(OopClosureType* closure, Klass* k); + template static bool do_metadata(OopClosureType* closure); +}; + +// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions. +#define nvs_nv_to_bool true +#define nvs_v_to_bool false +#define nvs_to_bool(nv_suffix) nvs##nv_suffix##_to_bool #endif // SHARE_VM_MEMORY_ITERATOR_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/iterator.inline.hpp --- a/hotspot/src/share/vm/memory/iterator.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/iterator.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -28,6 +28,12 @@ #include "classfile/classLoaderData.hpp" #include "memory/iterator.hpp" #include "oops/klass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" +#include "oops/instanceRefKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" +#include "oops/typeArrayKlass.inline.hpp" #include "utilities/debug.hpp" inline void MetadataAwareOopClosure::do_class_loader_data(ClassLoaderData* cld) { @@ -44,4 +50,63 @@ inline void MetadataAwareOopClosure::do_klass(Klass* k) { do_klass_nv(k); } +#ifdef ASSERT +// This verification is applied to all visited oops. +// The closures can turn is off by overriding should_verify_oops(). +template +void ExtendedOopClosure::verify(T* p) { + if (should_verify_oops()) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop o = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in_closed_subset(o), + err_msg("should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o))); + } + } +} +#endif + +// Implementation of the non-virtual do_oop dispatch. + +template +inline void Devirtualizer::do_oop(OopClosureType* closure, T* p) { + debug_only(closure->verify(p)); + closure->do_oop_nv(p); +} +template +inline void Devirtualizer::do_klass(OopClosureType* closure, Klass* k) { + closure->do_klass_nv(k); +} +template +inline bool Devirtualizer::do_metadata(OopClosureType* closure) { + // Make sure the non-virtual and the virtual versions match. + assert(closure->do_metadata_nv() == closure->do_metadata(), "Inconsistency in do_metadata"); + return closure->do_metadata_nv(); +} + +// Implementation of the virtual do_oop dispatch. + +template +void Devirtualizer::do_oop(OopClosureType* closure, T* p) { + debug_only(closure->verify(p)); + closure->do_oop(p); +} +template +void Devirtualizer::do_klass(OopClosureType* closure, Klass* k) { + closure->do_klass(k); +} +template +bool Devirtualizer::do_metadata(OopClosureType* closure) { + return closure->do_metadata(); +} + +// The list of all "specializable" oop_oop_iterate function definitions. +#define ALL_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_REF_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) + #endif // SHARE_VM_MEMORY_ITERATOR_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/sharedHeap.cpp --- a/hotspot/src/share/vm/memory/sharedHeap.cpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/stringTable.hpp" -#include "classfile/systemDictionary.hpp" -#include "code/codeCache.hpp" -#include "gc_interface/collectedHeap.inline.hpp" -#include "memory/sharedHeap.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.inline.hpp" -#include "runtime/fprofiler.hpp" -#include "runtime/java.hpp" -#include "utilities/copy.hpp" -#include "utilities/workgroup.hpp" - -SharedHeap* SharedHeap::_sh; - -SharedHeap::SharedHeap() : - CollectedHeap(), - _workers(NULL) -{ - _sh = this; // ch is static, should be set only once. - if (UseConcMarkSweepGC || UseG1GC) { - _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, - /* are_GC_task_threads */true, - /* are_ConcurrentGC_threads */false); - if (_workers == NULL) { - vm_exit_during_initialization("Failed necessary allocation."); - } else { - _workers->initialize_workers(); - } - } -} - -bool SharedHeap::heap_lock_held_for_gc() { - Thread* t = Thread::current(); - return Heap_lock->owned_by_self() - || ( (t->is_GC_task_thread() || t->is_VM_thread()) - && _thread_holds_heap_lock_for_gc); -} - -void SharedHeap::set_par_threads(uint t) { - assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); - _n_par_threads = t; -} - -SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* heap, bool activate) - : MarkScope(activate), _sh(heap) -{ - if (_active) { - Threads::change_thread_claim_parity(); - // Zero the claimed high water mark in the StringTable - StringTable::clear_parallel_claimed_index(); - } -} - -SharedHeap::StrongRootsScope::~StrongRootsScope() { - Threads::assert_all_threads_claimed(); -} - -void SharedHeap::set_barrier_set(BarrierSet* bs) { - _barrier_set = bs; - // Cached barrier set for fast access in oops - oopDesc::set_bs(bs); -} - -void SharedHeap::post_initialize() { - CollectedHeap::post_initialize(); - ref_processing_init(); -} - -void SharedHeap::ref_processing_init() {} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/sharedHeap.hpp --- a/hotspot/src/share/vm/memory/sharedHeap.hpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_MEMORY_SHAREDHEAP_HPP -#define SHARE_VM_MEMORY_SHAREDHEAP_HPP - -#include "gc_interface/collectedHeap.hpp" -#include "memory/generation.hpp" - -// A "SharedHeap" is an implementation of a java heap for HotSpot. This -// is an abstract class: there may be many different kinds of heaps. This -// class defines the functions that a heap must implement, and contains -// infrastructure common to all heaps. - -class Generation; -class BarrierSet; -class GenRemSet; -class Space; -class SpaceClosure; -class OopClosure; -class OopsInGenClosure; -class ObjectClosure; -class SubTasksDone; -class WorkGang; -class FlexibleWorkGang; -class CollectorPolicy; -class KlassClosure; - -// Note on use of FlexibleWorkGang's for GC. -// There are three places where task completion is determined. -// In -// 1) ParallelTaskTerminator::offer_termination() where _n_threads -// must be set to the correct value so that count of workers that -// have offered termination will exactly match the number -// working on the task. Tasks such as those derived from GCTask -// use ParallelTaskTerminator's. Tasks that want load balancing -// by work stealing use this method to gauge completion. -// 2) SubTasksDone has a variable _n_threads that is used in -// all_tasks_completed() to determine completion. all_tasks_complete() -// counts the number of tasks that have been done and then reset -// the SubTasksDone so that it can be used again. When the number of -// tasks is set to the number of GC workers, then _n_threads must -// be set to the number of active GC workers. G1RootProcessor and -// GenCollectedHeap have SubTasksDone. -// 3) SequentialSubTasksDone has an _n_threads that is used in -// a way similar to SubTasksDone and has the same dependency on the -// number of active GC workers. CompactibleFreeListSpace and Space -// have SequentialSubTasksDone's. -// -// Examples of using SubTasksDone and SequentialSubTasksDone: -// G1RootProcessor and GenCollectedHeap::process_roots() use -// SubTasksDone* _process_strong_tasks to claim tasks for workers -// -// GenCollectedHeap::gen_process_roots() calls -// rem_set()->younger_refs_iterate() -// to scan the card table and which eventually calls down into -// CardTableModRefBS::par_non_clean_card_iterate_work(). This method -// uses SequentialSubTasksDone* _pst to claim tasks. -// Both SubTasksDone and SequentialSubTasksDone call their method -// all_tasks_completed() to count the number of GC workers that have -// finished their work. That logic is "when all the workers are -// finished the tasks are finished". -// -// The pattern that appears in the code is to set _n_threads -// to a value > 1 before a task that you would like executed in parallel -// and then to set it to 0 after that task has completed. A value of -// 0 is a "special" value in set_n_threads() which translates to -// setting _n_threads to 1. -// -// Some code uses _n_termination to decide if work should be done in -// parallel. The notorious possibly_parallel_oops_do() in threads.cpp -// is an example of such code. Look for variable "is_par" for other -// examples. -// -// The active_workers is not reset to 0 after a parallel phase. It's -// value may be used in later phases and in one instance at least -// (the parallel remark) it has to be used (the parallel remark depends -// on the partitioning done in the previous parallel scavenge). - -class SharedHeap : public CollectedHeap { - friend class VMStructs; - - friend class VM_GC_Operation; - friend class VM_CGC_Operation; - -protected: - // There should be only a single instance of "SharedHeap" in a program. - // This is enforced with the protected constructor below, which will also - // set the static pointer "_sh" to that instance. - static SharedHeap* _sh; - - // If we're doing parallel GC, use this gang of threads. - FlexibleWorkGang* _workers; - - // Full initialization is done in a concrete subtype's "initialize" - // function. - SharedHeap(); - - // Returns true if the calling thread holds the heap lock, - // or the calling thread is a par gc thread and the heap_lock is held - // by the vm thread doing a gc operation. - bool heap_lock_held_for_gc(); - // True if the heap_lock is held by the a non-gc thread invoking a gc - // operation. - bool _thread_holds_heap_lock_for_gc; - -public: - static SharedHeap* heap() { return _sh; } - - void set_barrier_set(BarrierSet* bs); - - // Does operations required after initialization has been done. - virtual void post_initialize(); - - // Initialization of ("weak") reference processing support - virtual void ref_processing_init(); - - // Iteration functions. - void oop_iterate(ExtendedOopClosure* cl) = 0; - - // Iterate over all spaces in use in the heap, in an undefined order. - virtual void space_iterate(SpaceClosure* cl) = 0; - - // A SharedHeap will contain some number of spaces. This finds the - // space whose reserved area contains the given address, or else returns - // NULL. - virtual Space* space_containing(const void* addr) const = 0; - - bool no_gc_in_progress() { return !is_gc_active(); } - - // Note, the below comment needs to be updated to reflect the changes - // introduced by JDK-8076225. This should be done as part of JDK-8076289. - // - //Some collectors will perform "process_strong_roots" in parallel. - // Such a call will involve claiming some fine-grained tasks, such as - // scanning of threads. To make this process simpler, we provide the - // "strong_roots_parity()" method. Collectors that start parallel tasks - // whose threads invoke "process_strong_roots" must - // call "change_strong_roots_parity" in sequential code starting such a - // task. (This also means that a parallel thread may only call - // process_strong_roots once.) - // - // For calls to process_roots by sequential code, the parity is - // updated automatically. - // - // The idea is that objects representing fine-grained tasks, such as - // threads, will contain a "parity" field. A task will is claimed in the - // current "process_roots" call only if its parity field is the - // same as the "strong_roots_parity"; task claiming is accomplished by - // updating the parity field to the strong_roots_parity with a CAS. - // - // If the client meats this spec, then strong_roots_parity() will have - // the following properties: - // a) to return a different value than was returned before the last - // call to change_strong_roots_parity, and - // c) to never return a distinguished value (zero) with which such - // task-claiming variables may be initialized, to indicate "never - // claimed". - public: - - // Call these in sequential code around process_roots. - // strong_roots_prologue calls change_strong_roots_parity, if - // parallel tasks are enabled. - class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope { - SharedHeap* _sh; - - public: - StrongRootsScope(SharedHeap* heap, bool activate = true); - ~StrongRootsScope(); - }; - - private: - - public: - FlexibleWorkGang* workers() const { return _workers; } - - // The functions below are helper functions that a subclass of - // "SharedHeap" can use in the implementation of its virtual - // functions. - -public: - - // Do anything common to GC's. - virtual void gc_prologue(bool full) = 0; - virtual void gc_epilogue(bool full) = 0; - - // Sets the number of parallel threads that will be doing tasks - // (such as process roots) subsequently. - virtual void set_par_threads(uint t); -}; - -#endif // SHARE_VM_MEMORY_SHAREDHEAP_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/space.cpp --- a/hotspot/src/share/vm/memory/space.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/space.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -31,6 +31,7 @@ #include "memory/blockOffsetTable.inline.hpp" #include "memory/defNewGeneration.hpp" #include "memory/genCollectedHeap.hpp" +#include "memory/genOopClosures.inline.hpp" #include "memory/space.hpp" #include "memory/space.inline.hpp" #include "memory/universe.inline.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/strongRootsScope.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/strongRootsScope.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/stringTable.hpp" +#include "code/nmethod.hpp" +#include "memory/strongRootsScope.hpp" +#include "runtime/thread.hpp" + +MarkScope::MarkScope(bool activate) : _active(activate) { + if (_active) { + nmethod::oops_do_marking_prologue(); + } +} + +MarkScope::~MarkScope() { + if (_active) { + nmethod::oops_do_marking_epilogue(); + } +} + +StrongRootsScope::StrongRootsScope(bool activate) : MarkScope(activate) { + if (_active) { + Threads::change_thread_claim_parity(); + // Zero the claimed high water mark in the StringTable + StringTable::clear_parallel_claimed_index(); + } +} + +StrongRootsScope::~StrongRootsScope() { + Threads::assert_all_threads_claimed(); +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/strongRootsScope.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/strongRootsScope.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP +#define SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP + +#include "memory/allocation.hpp" + +class MarkScope : public StackObj { + protected: + bool _active; + public: + MarkScope(bool activate = true); + ~MarkScope(); +}; + +// Sets up and tears down the required state for parallel root processing. + +class StrongRootsScope : public MarkScope { + public: + StrongRootsScope(bool activate = true); + ~StrongRootsScope(); +}; + +#endif // SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/memory/tenuredGeneration.cpp --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -36,6 +36,9 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/parNew/parOopClosures.hpp" +#endif TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, int level, diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" -#include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" -#include "memory/iterator.inline.hpp" -#include "memory/oopFactory.hpp" -#include "memory/specialized_oop_closures.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/instanceClassLoaderKlass.hpp" -#include "oops/instanceMirrorKlass.hpp" -#include "oops/instanceOop.hpp" -#include "oops/oop.inline.hpp" -#include "oops/symbol.hpp" -#include "runtime/handles.inline.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#endif // INCLUDE_ALL_GCS - -// Macro to define InstanceClassLoaderKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. -// Since ClassLoader objects have only a pointer to the loader_data, they are not -// compressed nor does the pointer move. - -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)\ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); \ - /* cld can be null if we have a non-registered class loader. */ \ - if (cld != NULL) { \ - closure->do_class_loader_data(cld); \ - } \ - } \ - \ - return size; \ -} - -#if INCLUDE_ALL_GCS -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - return size; \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); \ - /* cld can be null if we have a non-registered class loader. */ \ - if (cld != NULL) { \ - closure->do_class_loader_data(cld); \ - } \ - } \ - } \ - \ - return size; \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) - -void InstanceClassLoaderKlass::oop_follow_contents(oop obj) { - InstanceKlass::oop_follow_contents(obj); - ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); - - // We must NULL check here, since the class loader - // can be found before the loader data has been set up. - if(loader_data != NULL) { - MarkSweep::follow_class_loader(loader_data); - } -} - -#if INCLUDE_ALL_GCS -void InstanceClassLoaderKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - InstanceKlass::oop_follow_contents(cm, obj); - ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); - if (loader_data != NULL) { - PSParallelCompact::follow_class_loader(cm, loader_data); - } -} - -void InstanceClassLoaderKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - InstanceKlass::oop_push_contents(pm, obj); - - // This is called by the young collector. It will already have taken care of - // all class loader data. So, we don't have to follow the class loader -> - // class loader data link. -} - -int InstanceClassLoaderKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - InstanceKlass::oop_update_pointers(cm, obj); - return size_helper(); -} -#endif // INCLUDE_ALL_GCS - diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -48,34 +48,60 @@ InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceClassLoaderKlass iterators also visit the CLD pointer (or mirror of anonymous klasses.) -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ + private: + // Forward iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + +#if INCLUDE_ALL_GCS + // Reverse iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif + + // Bounded range iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + public: + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // INCLUDE_ALL_GCS - // Garbage collection - void oop_follow_contents(oop obj); - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS }; #endif // SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "oops/instanceClassLoaderKlass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +inline int InstanceClassLoaderKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + int size = InstanceKlass::oop_oop_iterate(obj, closure); + + if (Devirtualizer::do_metadata(closure)) { + ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); + // cld can be null if we have a non-registered class loader. + if (cld != NULL) { + closure->do_class_loader_data(cld); + } + } + + return size; +} + +#if INCLUDE_ALL_GCS +template +inline int InstanceClassLoaderKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + int size = InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + assert(!Devirtualizer::do_metadata(closure), + "Code to handle metadata is not implemented"); + + return size; +} +#endif // INCLUDE_ALL_GCS + + +template +inline int InstanceClassLoaderKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + int size = InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); + // cld can be null if we have a non-registered class loader. + if (cld != NULL) { + closure->do_class_loader_data(cld); + } + } + } + + return size; +} + + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -28,12 +28,10 @@ #include "classfile/verifier.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/oopMapCache.hpp" #include "interpreter/rewriter.hpp" #include "jvmtifiles/jvmti.h" -#include "memory/genOopClosures.inline.hpp" #include "memory/heapInspection.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" @@ -41,7 +39,7 @@ #include "memory/specialized_oop_closures.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceClassLoaderKlass.hpp" -#include "oops/instanceKlass.hpp" +#include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" @@ -64,17 +62,6 @@ #include "services/threadService.hpp" #include "utilities/dtrace.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -1993,288 +1980,6 @@ } #endif //PRODUCT - -// Garbage collection - -#ifdef ASSERT -template void assert_is_in(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); - } -} -template void assert_is_in_closed_subset(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), - err_msg("should be in closed *p " INTPTR_FORMAT " " INTPTR_FORMAT, (address)p, (address)o)); - } -} -template void assert_is_in_reserved(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); - } -} -template void assert_nothing(T *p) {} - -#else -template void assert_is_in(T *p) {} -template void assert_is_in_closed_subset(T *p) {} -template void assert_is_in_reserved(T *p) {} -template void assert_nothing(T *p) {} -#endif // ASSERT - -// -// Macros that iterate over areas of oops which are specialized on type of -// oop pointer either narrow or wide, depending on UseCompressedOops -// -// Parameters are: -// T - type of oop to point to (either oop or narrowOop) -// start_p - starting pointer for region to iterate over -// count - number of oops or narrowOops to iterate over -// do_oop - action to perform on each oop (it's arbitrary C code which -// makes it more efficient to put in a macro rather than making -// it a template function) -// assert_fn - assert function which is template function because performance -// doesn't matter when enabled. -#define InstanceKlass_SPECIALIZED_OOP_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* p = (T*)(start_p); \ - T* const end = p + (count); \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - -#define InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* const start = (T*)(start_p); \ - T* p = start + (count); \ - while (start < p) { \ - --p; \ - (assert_fn)(p); \ - do_oop; \ - } \ -} - -#define InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE( \ - T, start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && \ - mask_bits((intptr_t)h, sizeof(T)-1) == 0, \ - "bounded region must be properly aligned"); \ - T* p = (T*)(start_p); \ - T* end = p + (count); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - - -// The following macros call specialized macros, passing either oop or -// narrowOop as the specialization type. These test the UseCompressedOops -// flag. -#define InstanceKlass_OOP_MAP_ITERATE(obj, do_oop, assert_fn) \ -{ \ - /* Compute oopmap block range. The common case \ - is nonstatic_oop_map_size == 1. */ \ - OopMapBlock* map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* const end_map = map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - ++map; \ - } \ - } else { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - ++map; \ - } \ - } \ -} - -#define InstanceKlass_OOP_MAP_REVERSE_ITERATE(obj, do_oop, assert_fn) \ -{ \ - OopMapBlock* const start_map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* map = start_map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (start_map < map) { \ - --map; \ - InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - } \ - } else { \ - while (start_map < map) { \ - --map; \ - InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - } \ - } \ -} - -#define InstanceKlass_BOUNDED_OOP_MAP_ITERATE(obj, low, high, do_oop, \ - assert_fn) \ -{ \ - /* Compute oopmap block range. The common case is \ - nonstatic_oop_map_size == 1, so we accept the \ - usually non-existent extra overhead of examining \ - all the maps. */ \ - OopMapBlock* map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* const end_map = map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - low, high, \ - do_oop, assert_fn) \ - ++map; \ - } \ - } else { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - low, high, \ - do_oop, assert_fn) \ - ++map; \ - } \ - } \ -} - -void InstanceKlass::oop_follow_contents(oop obj) { - assert(obj != NULL, "can't follow the content of NULL object"); - MarkSweep::follow_klass(obj->klass()); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#if INCLUDE_ALL_GCS -void InstanceKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - assert(obj != NULL, "can't follow the content of NULL object"); - PSParallelCompact::follow_klass(cm, obj->klass()); - // Only mark the header and let the scan of the meta-data mark - // everything else. - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // INCLUDE_ALL_GCS - -// closure's do_metadata() method dictates whether the given closure should be -// applied to the klass ptr in the object header. - -#define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* header */ \ - if_do_metadata_checked(closure, nv_suffix) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} - -#if INCLUDE_ALL_GCS -#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, \ - OopClosureType* closure) { \ - assert_should_ignore_metadata(closure, nv_suffix); \ - \ - /* instance variables */ \ - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ - obj, \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} -#endif // INCLUDE_ALL_GCS - -#define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - } \ - InstanceKlass_BOUNDED_OOP_MAP_ITERATE( \ - obj, mr.start(), mr.end(), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS - -int InstanceKlass::oop_adjust_pointers(oop obj) { - int size = size_helper(); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - MarkSweep::adjust_pointer(p), \ - assert_is_in) - return size; -} - -#if INCLUDE_ALL_GCS -void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ - obj, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -int InstanceKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - int size = size_helper(); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - PSParallelCompact::adjust_pointer(p), \ - assert_is_in) - return size; -} - -#endif // INCLUDE_ALL_GCS - void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) { @@ -2695,6 +2400,57 @@ return false; } +bool InstanceKlass::find_inner_classes_attr(instanceKlassHandle k, int* ooff, int* noff, TRAPS) { + constantPoolHandle i_cp(THREAD, k->constants()); + for (InnerClassesIterator iter(k); !iter.done(); iter.next()) { + int ioff = iter.inner_class_info_index(); + if (ioff != 0) { + // Check to see if the name matches the class we're looking for + // before attempting to find the class. + if (i_cp->klass_name_at_matches(k, ioff)) { + Klass* inner_klass = i_cp->klass_at(ioff, CHECK_false); + if (k() == inner_klass) { + *ooff = iter.outer_class_info_index(); + *noff = iter.inner_name_index(); + return true; + } + } + } + } + return false; +} + +Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, bool* inner_is_member, TRAPS) { + instanceKlassHandle outer_klass; + *inner_is_member = false; + int ooff = 0, noff = 0; + if (find_inner_classes_attr(k, &ooff, &noff, THREAD)) { + constantPoolHandle i_cp(THREAD, k->constants()); + if (ooff != 0) { + Klass* ok = i_cp->klass_at(ooff, CHECK_NULL); + outer_klass = instanceKlassHandle(THREAD, ok); + *inner_is_member = true; + } + if (outer_klass.is_null()) { + // It may be anonymous; try for that. + int encl_method_class_idx = k->enclosing_method_class_index(); + if (encl_method_class_idx != 0) { + Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL); + outer_klass = instanceKlassHandle(THREAD, ok); + *inner_is_member = false; + } + } + } + + // If no inner class attribute found for this class. + if (outer_klass.is_null()) return NULL; + + // Throws an exception if outer klass has not declared k as an inner klass + // We need evidence that each klass knows about the other, or else + // the system could allow a spoof of an inner class to gain access rights. + Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL); + return outer_klass(); +} jint InstanceKlass::compute_modifier_flags(TRAPS) const { jint access = access_flags().as_int(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -406,13 +406,17 @@ bool is_same_class_package(oop classloader2, Symbol* classname2); static bool is_same_class_package(oop class_loader1, Symbol* class_name1, oop class_loader2, Symbol* class_name2); - // find an enclosing class (defined where original code was, in jvm.cpp!) + // find an enclosing class Klass* compute_enclosing_class(bool* inner_is_member, TRAPS) { instanceKlassHandle self(THREAD, this); return compute_enclosing_class_impl(self, inner_is_member, THREAD); } static Klass* compute_enclosing_class_impl(instanceKlassHandle self, - bool* inner_is_member, TRAPS); + bool* inner_is_member, TRAPS); + + // Find InnerClasses attribute for k and return outer_class_info_index & inner_name_index. + static bool find_inner_classes_attr(instanceKlassHandle k, + int* ooff, int* noff, TRAPS); // tell if two classes have the same enclosing class (at package level) bool is_same_package_member(Klass* class2, TRAPS) { @@ -965,10 +969,6 @@ void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed); #endif // INCLUDE_JVMTI - // Garbage collection - void oop_follow_contents(oop obj); - int oop_adjust_pointers(oop obj); - void clean_implementors_list(BoolObjectClosure* is_alive); void clean_method_data(BoolObjectClosure* is_alive); void clean_dependent_nmethods(); @@ -992,32 +992,108 @@ static void notify_unload_class(InstanceKlass* ik); static void release_C_heap_structures(InstanceKlass* ik); - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS - // Naming const char* signature_name() const; - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceKlass iterators also visits the Object's klass. + + // Forward iteration + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure); + - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Reverse iteration +#if INCLUDE_ALL_GCS + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure); +#endif + -#define InstanceKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ - int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, \ - MemRegion mr); + // Bounded range iteration + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr); + + + public: + +#define InstanceKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP + +#include "memory/iterator.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// The iteration over the oops in objects is a hot path in the GC code. +// By force inlining the following functions, we get similar GC performance +// as the previous macro based implementation. +#ifdef TARGET_COMPILER_visCPP +#define INLINE __forceinline +#else +#define INLINE inline +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) { + T* p = (T*)obj->obj_field_addr(map->offset()); + T* const end = p + map->count(); + + for (; p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) { + T* const start = (T*)obj->obj_field_addr(map->offset()); + T* p = start + map->count(); + + while (start < p) { + --p; + Devirtualizer::do_oop(closure, p); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) { + T* p = (T*)obj->obj_field_addr(map->offset()); + T* end = p + map->count(); + + T* const l = (T*)mr.start(); + T* const h = (T*)mr.end(); + assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && + mask_bits((intptr_t)h, sizeof(T)-1) == 0, + "bounded region must be properly aligned"); + + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) { + OopMapBlock* map = start_of_nonstatic_oop_maps(); + OopMapBlock* const end_map = map + nonstatic_oop_map_count(); + + for (; map < end_map; ++map) { + oop_oop_iterate_oop_map(map, obj, closure); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) { + OopMapBlock* const start_map = start_of_nonstatic_oop_maps(); + OopMapBlock* map = start_map + nonstatic_oop_map_count(); + + while (start_map < map) { + --map; + oop_oop_iterate_oop_map_reverse(map, obj, closure); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + OopMapBlock* map = start_of_nonstatic_oop_maps(); + OopMapBlock* const end_map = map + nonstatic_oop_map_count(); + + for (;map < end_map; ++map) { + oop_oop_iterate_oop_map_bounded(map, obj, closure, mr); + } +} + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized(obj, closure); + } else { + oop_oop_iterate_oop_maps_specialized(obj, closure); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized_reverse(obj, closure); + } else { + oop_oop_iterate_oop_maps_specialized_reverse(obj, closure); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized_bounded(obj, closure, mr); + } else { + oop_oop_iterate_oop_maps_specialized_bounded(obj, closure, mr); + } +} + +template +INLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, this); + } + + oop_oop_iterate_oop_maps(obj, closure); + + return size_helper(); +} + +#if INCLUDE_ALL_GCS +template +INLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + assert(!Devirtualizer::do_metadata(closure), + "Code to handle metadata is not implemented"); + + oop_oop_iterate_oop_maps_reverse(obj, closure); + + return size_helper(); +} +#endif + +template +INLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + Devirtualizer::do_klass(closure, this); + } + } + + oop_oop_iterate_oop_maps_bounded(obj, closure, mr); + + return size_helper(); +} + +#undef INLINE + + +#define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + +#define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceMirrorKlass.cpp --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,9 +25,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/specialized_oop_closures.hpp" @@ -38,313 +36,9 @@ #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::_offset_of_static_fields = 0; -#ifdef ASSERT -template void assert_is_in(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); - } -} -template void assert_is_in_closed_subset(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), "should be in closed"); - } -} -template void assert_is_in_reserved(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); - } -} -template void assert_nothing(T *p) {} - -#else -template void assert_is_in(T *p) {} -template void assert_is_in_closed_subset(T *p) {} -template void assert_is_in_reserved(T *p) {} -template void assert_nothing(T *p) {} -#endif // ASSERT - -#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* p = (T*)(start_p); \ - T* const end = p + (count); \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - -#define InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE( \ - T, start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && \ - mask_bits((intptr_t)h, sizeof(T)-1) == 0, \ - "bounded region must be properly aligned"); \ - T* p = (T*)(start_p); \ - T* end = p + (count); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - - -#define InstanceMirrorKlass_OOP_ITERATE(start_p, count, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - do_oop, assert_fn) \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(oop, \ - start_p, count, \ - do_oop, assert_fn) \ - } \ -} - -// The following macros call specialized macros, passing either oop or -// narrowOop as the specialization type. These test the UseCompressedOops -// flag. -#define InstanceMirrorKlass_BOUNDED_OOP_ITERATE(start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } \ -} - - -void InstanceMirrorKlass::oop_follow_contents(oop obj) { - InstanceKlass::oop_follow_contents(obj); - - // Follow the klass field in the mirror. - Klass* klass = java_lang_Class::as_Klass(obj); - if (klass != NULL) { - // An anonymous class doesn't have its own class loader, so the call - // to follow_klass will mark and push its java mirror instead of the - // class loader. When handling the java mirror for an anonymous class - // we need to make sure its class loader data is claimed, this is done - // by calling follow_class_loader explicitly. For non-anonymous classes - // the call to follow_class_loader is made when the class loader itself - // is handled. - if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { - MarkSweep::follow_class_loader(klass->class_loader_data()); - } else { - MarkSweep::follow_klass(klass); - } - } else { - // If klass is NULL then this a mirror for a primitive type. - // We don't have to follow them, since they are handled as strong - // roots in Universe::oops_do. - assert(java_lang_Class::is_primitive(obj), "Sanity check"); - } - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#if INCLUDE_ALL_GCS -void InstanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - InstanceKlass::oop_follow_contents(cm, obj); - - // Follow the klass field in the mirror. - Klass* klass = java_lang_Class::as_Klass(obj); - if (klass != NULL) { - // An anonymous class doesn't have its own class loader, so the call - // to follow_klass will mark and push its java mirror instead of the - // class loader. When handling the java mirror for an anonymous class - // we need to make sure its class loader data is claimed, this is done - // by calling follow_class_loader explicitly. For non-anonymous classes - // the call to follow_class_loader is made when the class loader itself - // is handled. - if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { - PSParallelCompact::follow_class_loader(cm, klass->class_loader_data()); - } else { - PSParallelCompact::follow_klass(cm, klass); - } - } else { - // If klass is NULL then this a mirror for a primitive type. - // We don't have to follow them, since they are handled as strong - // roots in Universe::oops_do. - assert(java_lang_Class::is_primitive(obj), "Sanity check"); - } - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // INCLUDE_ALL_GCS - -int InstanceMirrorKlass::oop_adjust_pointers(oop obj) { - int size = oop_size(obj); - InstanceKlass::oop_adjust_pointers(obj); - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - MarkSweep::adjust_pointer(p), \ - assert_nothing) - return size; -} - -#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(T, nv_suffix) \ - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return oop_size(obj); \ - -#define InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(T, nv_suffix, mr) \ - InstanceMirrorKlass_BOUNDED_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - mr.start(), mr.end(), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return oop_size(obj); \ - - -// Macro to define InstanceMirrorKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. - -#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - Klass* klass = java_lang_Class::as_Klass(obj); \ - /* We'll get NULL for primitive mirrors. */ \ - if (klass != NULL) { \ - closure->do_klass##nv_suffix(klass); \ - } \ - } \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ - } \ -} - -#if INCLUDE_ALL_GCS -#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ - } \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - Klass* klass = java_lang_Class::as_Klass(obj); \ - /* We'll get NULL for primitive mirrors. */ \ - if (klass != NULL) { \ - closure->do_klass##nv_suffix(klass); \ - } \ - } \ - } \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr); \ - } else { \ - InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr); \ - } \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) - -#if INCLUDE_ALL_GCS -void InstanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - // Note that we don't have to follow the mirror -> klass pointer, since all - // klasses that are dirty will be scavenged when we iterate over the - // ClassLoaderData objects. - - InstanceKlass::oop_push_contents(pm, obj); - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -int InstanceMirrorKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - int size = oop_size(obj); - InstanceKlass::oop_update_pointers(cm, obj); - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ - PSParallelCompact::adjust_pointer(p), \ - assert_nothing) - return size; -} -#endif // INCLUDE_ALL_GCS - int InstanceMirrorKlass::instance_size(KlassHandle k) { if (k() != NULL && k->oop_is_instance()) { return align_object_size(size_helper() + InstanceKlass::cast(k())->static_field_size()); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceMirrorKlass.hpp --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -88,19 +88,66 @@ // allocation instanceOop allocate_instance(KlassHandle k, TRAPS); - // Garbage collection - int oop_adjust_pointers(oop obj); - void oop_follow_contents(oop obj); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceMirrorKlass iterators also visit the hidden Klass pointer. + + public: + // Iterate over the static fields. + template + inline void oop_oop_iterate_statics(oop obj, OopClosureType* closure); + + private: + // Iterate over the static fields. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_statics_specialized(oop obj, OopClosureType* closure); - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Forward iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + + // Reverse iteration +#if INCLUDE_ALL_GCS + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif + + + // Bounded range iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over the static fields. + template + inline void oop_oop_iterate_statics_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over the static fields. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_statics_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + + public: #define InstanceMirrorKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,164 @@ +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_specialized(oop obj, OopClosureType* closure) { + T* p = (T*)start_of_static_fields(obj); + T* const end = p + java_lang_Class::static_oop_field_count(obj); + + for (; p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void InstanceMirrorKlass::oop_oop_iterate_statics(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_statics_specialized(obj, closure); + } else { + oop_oop_iterate_statics_specialized(obj, closure); + } +} + +template +int InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + InstanceKlass::oop_oop_iterate(obj, closure); + + if (Devirtualizer::do_metadata(closure)) { + Klass* klass = java_lang_Class::as_Klass(obj); + // We'll get NULL for primitive mirrors. + if (klass != NULL) { + Devirtualizer::do_klass(closure, klass); + } + } + + oop_oop_iterate_statics(obj, closure); + + return oop_size(obj); +} + +#if INCLUDE_ALL_GCS +template +int InstanceMirrorKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + InstanceMirrorKlass::oop_oop_iterate_statics(obj, closure); + + return oop_size(obj); +} +#endif + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_specialized_bounded(oop obj, + OopClosureType* closure, + MemRegion mr) { + T* p = (T*)start_of_static_fields(obj); + T* end = p + java_lang_Class::static_oop_field_count(obj); + + T* const l = (T*)mr.start(); + T* const h = (T*)mr.end(); + assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && + mask_bits((intptr_t)h, sizeof(T)-1) == 0, + "bounded region must be properly aligned"); + + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_statics_specialized_bounded(obj, closure, mr); + } else { + oop_oop_iterate_statics_specialized_bounded(obj, closure, mr); + } +} + +template +int InstanceMirrorKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + Klass* klass = java_lang_Class::as_Klass(obj); + // We'll get NULL for primitive mirrors. + if (klass != NULL) { + Devirtualizer::do_klass(closure, klass); + } + } + } + + oop_oop_iterate_statics_bounded(obj, closure, mr); + + return oop_size(obj); +} + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceRefKlass.cpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,421 +25,16 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" -#include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/genCollectedHeap.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/specialized_oop_closures.hpp" -#include "oops/instanceRefKlass.hpp" +#include "oops/instanceRefKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/preserveException.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -template -void specialized_oop_follow_contents(InstanceRefKlass* ref, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - T heap_oop = oopDesc::load_heap_oop(referent_addr); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); - } - ) - if (!oopDesc::is_null(heap_oop)) { - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); - if (!referent->is_gc_marked() && - MarkSweep::ref_processor()->discover_reference(obj, ref->reference_type())) { - // reference was discovered, referent will be traversed later - ref->InstanceKlass::oop_follow_contents(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); - } - ) - return; - } else { - // treat referent as normal oop - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); - } - ) - MarkSweep::mark_and_push(referent_addr); - } - } - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - MarkSweep::mark_and_push(discovered_addr); - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - oop next = oopDesc::load_decode_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - // treat next as normal oop. next is a link in the reference queue. - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process next as normal " INTPTR_FORMAT, next_addr); - } - ) - MarkSweep::mark_and_push(next_addr); - ref->InstanceKlass::oop_follow_contents(obj); -} - -void InstanceRefKlass::oop_follow_contents(oop obj) { - if (UseCompressedOops) { - specialized_oop_follow_contents(this, obj); - } else { - specialized_oop_follow_contents(this, obj); - } -} - -#if INCLUDE_ALL_GCS -template -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( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); - } - ) - if (!oopDesc::is_null(heap_oop)) { - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); - if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && - PSParallelCompact::ref_processor()-> - discover_reference(obj, ref->reference_type())) { - // reference already enqueued, referent will be traversed later - ref->InstanceKlass::oop_follow_contents(cm, obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); - } - ) - return; - } else { - // treat referent as normal oop - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); - } - ) - PSParallelCompact::mark_and_push(cm, referent_addr); - } - } - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - PSParallelCompact::mark_and_push(cm, discovered_addr); - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - T next = oopDesc::load_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - PSParallelCompact::mark_and_push(cm, next_addr); - ref->InstanceKlass::oop_follow_contents(cm, obj); -} - -void InstanceRefKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - if (UseCompressedOops) { - specialized_oop_follow_contents(this, cm, obj); - } else { - specialized_oop_follow_contents(this, cm, obj); - } -} -#endif // INCLUDE_ALL_GCS - -#ifdef ASSERT -template void trace_reference_gc(const char *s, oop obj, - T* referent_addr, - T* next_addr, - T* discovered_addr) { - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("%s obj " INTPTR_FORMAT, s, (address)obj); - gclog_or_tty->print_cr(" referent_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, referent_addr, - referent_addr ? - (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL); - gclog_or_tty->print_cr(" next_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, next_addr, - next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL); - gclog_or_tty->print_cr(" discovered_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, discovered_addr, - discovered_addr ? - (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL); - } -} -#endif - -template void specialized_oop_adjust_pointers(InstanceRefKlass *ref, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - MarkSweep::adjust_pointer(referent_addr); - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - MarkSweep::adjust_pointer(next_addr); - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - MarkSweep::adjust_pointer(discovered_addr); - debug_only(trace_reference_gc("InstanceRefKlass::oop_adjust_pointers", obj, - referent_addr, next_addr, discovered_addr);) -} - -int InstanceRefKlass::oop_adjust_pointers(oop obj) { - int size = size_helper(); - InstanceKlass::oop_adjust_pointers(obj); - - if (UseCompressedOops) { - specialized_oop_adjust_pointers(this, obj); - } else { - specialized_oop_adjust_pointers(this, obj); - } - return size; -} - -#define InstanceRefKlass_SPECIALIZED_OOP_ITERATE(T, nv_suffix, contains) \ - T* disc_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); \ - if (closure->apply_to_weak_ref_discovered_field()) { \ - closure->do_oop##nv_suffix(disc_addr); \ - } \ - \ - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); \ - T heap_oop = oopDesc::load_heap_oop(referent_addr); \ - ReferenceProcessor* rp = closure->_ref_processor; \ - if (!oopDesc::is_null(heap_oop)) { \ - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); \ - if (!referent->is_gc_marked() && (rp != NULL) && \ - rp->discover_reference(obj, reference_type())) { \ - return size; \ - } else if (contains(referent_addr)) { \ - /* treat referent as normal oop */ \ - closure->do_oop##nv_suffix(referent_addr); \ - } \ - } \ - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); \ - if (ReferenceProcessor::pending_list_uses_discovered_field()) { \ - T next_oop = oopDesc::load_heap_oop(next_addr); \ - /* Treat discovered as normal oop, if ref is not "active" (next non-NULL) */\ - if (!oopDesc::is_null(next_oop) && contains(disc_addr)) { \ - /* i.e. ref is not "active" */ \ - debug_only( \ - if(TraceReferenceGC && PrintGCDetails) { \ - gclog_or_tty->print_cr(" Process discovered as normal " \ - INTPTR_FORMAT, disc_addr); \ - } \ - ) \ - closure->do_oop##nv_suffix(disc_addr); \ - } \ - } else { \ - /* In the case of older JDKs which do not use the discovered field for */ \ - /* the pending list, an inactive ref (next != NULL) must always have a */ \ - /* NULL discovered field. */ \ - debug_only( \ - T next_oop = oopDesc::load_heap_oop(next_addr); \ - T disc_oop = oopDesc::load_heap_oop(disc_addr); \ - assert(oopDesc::is_null(next_oop) || oopDesc::is_null(disc_oop), \ - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL" \ - "discovered field", (oopDesc*)obj)); \ - ) \ - } \ - /* treat next as normal oop */ \ - if (contains(next_addr)) { \ - closure->do_oop##nv_suffix(next_addr); \ - } \ - return size; \ - - -template bool contains(T *t) { return true; } - -// Macro to define InstanceRefKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. - -#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ - } \ -} - -#if INCLUDE_ALL_GCS -#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ - } \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr.contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr.contains); \ - } \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) - -#if INCLUDE_ALL_GCS -template -void specialized_oop_push_contents(InstanceRefKlass *ref, - PSPromotionManager* pm, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - if (PSScavenge::should_scavenge(referent_addr)) { - ReferenceProcessor* rp = PSScavenge::reference_processor(); - if (rp->discover_reference(obj, ref->reference_type())) { - // reference already enqueued, referent and next will be traversed later - ref->InstanceKlass::oop_push_contents(pm, obj); - return; - } else { - // treat referent as normal oop - pm->claim_or_forward_depth(referent_addr); - } - } - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - if (PSScavenge::should_scavenge(discovered_addr)) { - pm->claim_or_forward_depth(discovered_addr); - } - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - oop next = oopDesc::load_decode_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - - // Treat next as normal oop; next is a link in the reference queue. - if (PSScavenge::should_scavenge(next_addr)) { - pm->claim_or_forward_depth(next_addr); - } - ref->InstanceKlass::oop_push_contents(pm, obj); -} - -void InstanceRefKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - if (UseCompressedOops) { - specialized_oop_push_contents(this, pm, obj); - } else { - specialized_oop_push_contents(this, pm, obj); - } -} - -template -void specialized_oop_update_pointers(InstanceRefKlass *ref, - ParCompactionManager* cm, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - PSParallelCompact::adjust_pointer(referent_addr); - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - PSParallelCompact::adjust_pointer(next_addr); - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - PSParallelCompact::adjust_pointer(discovered_addr); - debug_only(trace_reference_gc("InstanceRefKlass::oop_update_ptrs", obj, - referent_addr, next_addr, discovered_addr);) -} - -int InstanceRefKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - InstanceKlass::oop_update_pointers(cm, obj); - if (UseCompressedOops) { - specialized_oop_update_pointers(this, cm, obj); - } else { - specialized_oop_update_pointers(this, cm, obj); - } - return size_helper(); -} -#endif // INCLUDE_ALL_GCS - void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent // and nextPending field. They are treated specially by the @@ -483,12 +78,6 @@ InstanceKlass::oop_verify_on(obj, st); // Verify referent field oop referent = java_lang_ref_Reference::referent(obj); - - // We should make this general to all heaps - GenCollectedHeap* gch = NULL; - if (Universe::heap()->kind() == CollectedHeap::GenCollectedHeap) - gch = GenCollectedHeap::heap(); - if (referent != NULL) { guarantee(referent->is_oop(), "referent field heap failed"); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceRefKlass.hpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -64,30 +64,71 @@ return (InstanceRefKlass*) k; } - // Garbage collection - int oop_adjust_pointers(oop obj); - void oop_follow_contents(oop obj); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceRefKlass iterators also support reference processing. + + + // Forward iteration +private: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Reverse iteration +#if INCLUDE_ALL_GCS + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif // INCLUDE_ALL_GCS + + // Bounded range iteration + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Reference processing part of the iterators. -#define InstanceRefKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ - int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr); + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_ref_processing_specialized(oop obj, OopClosureType* closure, Contains& contains); + + // Only perform reference processing if the referent object is within mr. + template + inline void oop_oop_iterate_ref_processing_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Reference processing + template + inline void oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure); + + + public: + +#define InstanceRefKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "memory/referenceProcessor.hpp" +#include "oops/instanceRefKlass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing_specialized(oop obj, OopClosureType* closure, Contains& contains) { + T* disc_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + if (closure->apply_to_weak_ref_discovered_field()) { + Devirtualizer::do_oop(closure, disc_addr); + } + + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + ReferenceProcessor* rp = closure->_ref_processor; + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (!referent->is_gc_marked() && (rp != NULL) && + rp->discover_reference(obj, reference_type())) { + return; + } else if (contains(referent_addr)) { + // treat referent as normal oop + Devirtualizer::do_oop(closure, referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + T next_oop = oopDesc::load_heap_oop(next_addr); + // Treat discovered as normal oop, if ref is not "active" (next non-NULL) + if (!oopDesc::is_null(next_oop) && contains(disc_addr)) { + // i.e. ref is not "active" + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(disc_addr)); + } + ) + Devirtualizer::do_oop(closure, disc_addr); + } + } else { + // In the case of older JDKs which do not use the discovered field for + // the pending list, an inactive ref (next != NULL) must always have a + // NULL discovered field. + debug_only( + T next_oop = oopDesc::load_heap_oop(next_addr); + T disc_oop = oopDesc::load_heap_oop(disc_addr); + assert(oopDesc::is_null(next_oop) || oopDesc::is_null(disc_oop), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL" + "discovered field", p2i(obj))); + ) + } + // treat next as normal oop + if (contains(next_addr)) { + Devirtualizer::do_oop(closure, next_addr); + } +} + +class AlwaysContains { + public: + template bool operator()(T* p) const { return true; } +}; + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure) { + AlwaysContains always_contains; + if (UseCompressedOops) { + oop_oop_iterate_ref_processing_specialized(obj, closure, always_contains); + } else { + oop_oop_iterate_ref_processing_specialized(obj, closure, always_contains); + } +} + +class MrContains { + const MemRegion _mr; + public: + MrContains(MemRegion mr) : _mr(mr) {} + template bool operator()(T* p) const { return _mr.contains(p); } +}; + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + const MrContains contains(mr); + if (UseCompressedOops) { + oop_oop_iterate_ref_processing_specialized(obj, closure, contains); + } else { + oop_oop_iterate_ref_processing_specialized(obj, closure, contains); + } +} + +template +int InstanceRefKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate(obj, closure); + + oop_oop_iterate_ref_processing(obj, closure); + + return size; +} + +#if INCLUDE_ALL_GCS +template +int InstanceRefKlass:: +oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + oop_oop_iterate_ref_processing(obj, closure); + + return size; +} +#endif // INCLUDE_ALL_GCS + + +template +int InstanceRefKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + oop_oop_iterate_ref_processing_bounded(obj, closure, mr); + + return size; +} + +// Macro to define InstanceRefKlass::oop_oop_iterate for virtual/nonvirtual for +// all closures. Macros calling macros above for each oop size. + +#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_REF_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + + +#endif // SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/klass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -27,7 +27,6 @@ #include "classfile/dictionary.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" @@ -43,9 +42,6 @@ #include "utilities/stack.inline.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" #endif // INCLUDE_ALL_GCS void Klass::set_name(Symbol* n) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/klass.hpp --- a/hotspot/src/share/vm/oops/klass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/klass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,21 +25,14 @@ #ifndef SHARE_VM_OOPS_KLASS_HPP #define SHARE_VM_OOPS_KLASS_HPP -#include "memory/genOopClosures.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" #include "memory/specialized_oop_closures.hpp" -#include "oops/klassPS.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" #include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" -#include "gc_implementation/g1/g1OopClosures.hpp" -#include "gc_implementation/parNew/parOopClosures.hpp" -#endif // INCLUDE_ALL_GCS // // A Klass provides: @@ -61,6 +54,7 @@ class ClassLoaderData; class klassVtable; class ParCompactionManager; +class PSPromotionManager; class KlassSizeStats; class fieldDescriptor; @@ -478,13 +472,6 @@ // and the package separators as '/'. virtual const char* signature_name() const; - // garbage collection support - virtual void oop_follow_contents(oop obj) = 0; - virtual int oop_adjust_pointers(oop obj) = 0; - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS_PV - // type testing operations protected: virtual bool oop_is_instance_slow() const { return false; } @@ -581,60 +568,35 @@ clean_weak_klass_links(is_alive, false /* clean_alive_klasses */); } - // iterators - virtual int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) = 0; - virtual int oop_oop_iterate_v(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate(obj, blk); - } + // GC specific object visitors + // + // Mark Sweep + virtual void oop_ms_follow_contents(oop obj) = 0; + virtual int oop_ms_adjust_pointers(oop obj) = 0; +#if INCLUDE_ALL_GCS + // Parallel Scavenge + virtual void oop_ps_push_contents( oop obj, PSPromotionManager* pm) = 0; + // Parallel Compact + virtual void oop_pc_follow_contents(oop obj, ParCompactionManager* cm) = 0; + virtual void oop_pc_update_pointers(oop obj) = 0; +#endif + + // Iterators specialized to particular subtypes + // of ExtendedOopClosure, to avoid closure virtual calls. +#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) = 0; \ + /* Iterates "closure" over all the oops in "obj" (of type "this") within "mr". */ \ + virtual int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) = 0; + + ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS - // In case we don't have a specialized backward scanner use forward - // iteration. - virtual int oop_oop_iterate_backwards_v(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } -#endif // INCLUDE_ALL_GCS - - // Iterates "blk" over all the oops in "obj" (of type "this") within "mr". - // (I don't see why the _m should be required, but without it the Solaris - // C++ gives warning messages about overridings of the "oop_oop_iterate" - // defined above "hiding" this virtual function. (DLD, 6/20/00)) */ - virtual int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) = 0; - virtual int oop_oop_iterate_v_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_m(obj, blk, mr); - } +#define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) = 0; - // Versions of the above iterators specialized to particular subtypes - // of OopClosure, to avoid closure virtual calls. -#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk) { \ - /* Default implementation reverts to general version. */ \ - return oop_oop_iterate(obj, blk); \ - } \ - \ - /* Iterates "blk" over all the oops in "obj" (of type "this") within "mr". \ - (I don't see why the _m should be required, but without it the Solaris \ - C++ gives warning messages about overridings of the "oop_oop_iterate" \ - defined above "hiding" this virtual function. (DLD, 6/20/00)) */ \ - virtual int oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* blk, \ - MemRegion mr) { \ - return oop_oop_iterate_m(obj, blk, mr); \ - } - - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) - -#if INCLUDE_ALL_GCS -#define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, \ - OopClosureType* blk) { \ - /* Default implementation reverts to general version. */ \ - return oop_oop_iterate_backwards_v(obj, blk); \ - } - - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // INCLUDE_ALL_GCS virtual void array_klasses_do(void f(Klass* k)) {} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/klassPS.hpp --- a/hotspot/src/share/vm/oops/klassPS.hpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_OOPS_KLASSPS_HPP -#define SHARE_VM_OOPS_KLASSPS_HPP - - // Expands to Parallel Scavenge and Parallel Old declarations - -#include "utilities/macros.hpp" - -#if INCLUDE_ALL_GCS -#define PARALLEL_GC_DECLS \ - virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ - /* Parallel Old GC support \ - \ - The 2-arg version of oop_update_pointers is for objects that are \ - known not to cross chunk boundaries. The 4-arg version is for \ - objects that do (or may) cross chunk boundaries; it updates only those \ - oops that are in the region [beg_addr, end_addr). */ \ - virtual void oop_follow_contents(ParCompactionManager* cm, oop obj); \ - virtual int oop_update_pointers(ParCompactionManager* cm, oop obj); - -// Pure virtual version for klass.hpp -#define PARALLEL_GC_DECLS_PV \ - virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ - virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ - virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; -#else // INCLUDE_ALL_GCS -#define PARALLEL_GC_DECLS -#define PARALLEL_GC_DECLS_PV -#endif // INCLUDE_ALL_GCS - -#endif // SHARE_VM_OOPS_KLASSPS_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/methodData.cpp --- a/hotspot/src/share/vm/oops/methodData.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/methodData.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -152,6 +152,7 @@ void BitData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BitData", extra); + st->cr(); } // ================================================================== diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/methodData.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -2056,7 +2056,7 @@ // Whole-method sticky bits and flags enum { - _trap_hist_limit = 21, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 22, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/objArrayKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,9 +26,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" #include "memory/resourceArea.hpp" @@ -45,17 +43,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/copy.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS) { assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(), @@ -410,179 +397,6 @@ bottom_klass()->initialize(THREAD); // dispatches to either InstanceKlass or TypeArrayKlass } -#define ObjArrayKlass_SPECIALIZED_OOP_ITERATE(T, a, p, do_oop) \ -{ \ - T* p = (T*)(a)->base(); \ - T* const end = p + (a)->length(); \ - while (p < end) { \ - do_oop; \ - p++; \ - } \ -} - -#define ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(T, a, p, low, high, do_oop) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - T* p = (T*)(a)->base(); \ - T* end = p + (a)->length(); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - do_oop; \ - ++p; \ - } \ -} - -#define ObjArrayKlass_OOP_ITERATE(a, p, do_oop) \ - if (UseCompressedOops) { \ - ObjArrayKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - a, p, do_oop) \ - } else { \ - ObjArrayKlass_SPECIALIZED_OOP_ITERATE(oop, \ - a, p, do_oop) \ - } - -#define ObjArrayKlass_BOUNDED_OOP_ITERATE(a, p, low, high, do_oop) \ - if (UseCompressedOops) { \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - a, p, low, high, do_oop) \ - } else { \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - a, p, low, high, do_oop) \ - } - -void ObjArrayKlass::oop_follow_contents(oop obj) { - assert (obj->is_array(), "obj must be array"); - MarkSweep::follow_klass(obj->klass()); - if (UseCompressedOops) { - objarray_follow_contents(obj, 0); - } else { - objarray_follow_contents(obj, 0); - } -} - -#if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - assert(obj->is_array(), "obj must be array"); - PSParallelCompact::follow_klass(cm, obj->klass()); - if (UseCompressedOops) { - objarray_follow_contents(cm, obj, 0); - } else { - objarray_follow_contents(cm, obj, 0); - } -} -#endif // INCLUDE_ALL_GCS - -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj, \ - OopClosureType* closure) { \ - assert (obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call. */ \ - int size = a->object_size(); \ - if_do_metadata_checked(closure, nv_suffix) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - ObjArrayKlass_OOP_ITERATE(a, p, (closure)->do_oop##nv_suffix(p)) \ - return size; \ -} - -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - assert(obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call */ \ - int size = a->object_size(); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_BOUNDED_OOP_ITERATE( \ - a, p, mr.start(), mr.end(), (closure)->do_oop##nv_suffix(p)) \ - return size; \ -} - -// Like oop_oop_iterate but only iterates over a specified range and only used -// for objArrayOops. -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj, \ - OopClosureType* closure, \ - int start, int end) { \ - assert(obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call */ \ - int size = a->object_size(); \ - if (UseCompressedOops) { \ - HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr(start);\ - /* this might be wierd if end needs to be aligned on HeapWord boundary */ \ - HeapWord* high = (HeapWord*)((narrowOop*)a->base() + end); \ - MemRegion mr(low, high); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - a, p, low, high, (closure)->do_oop##nv_suffix(p)) \ - } else { \ - HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr(start); \ - HeapWord* high = (HeapWord*)((oop*)a->base() + end); \ - MemRegion mr(low, high); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - a, p, low, high, (closure)->do_oop##nv_suffix(p)) \ - } \ - return size; \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r) - -int ObjArrayKlass::oop_adjust_pointers(oop obj) { - assert(obj->is_objArray(), "obj must be obj array"); - objArrayOop a = objArrayOop(obj); - // Get size before changing pointers. - // Don't call size() or oop_size() since that is a virtual call. - int size = a->object_size(); - ObjArrayKlass_OOP_ITERATE(a, p, MarkSweep::adjust_pointer(p)) - return size; -} - -#if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_objArray(), "obj must be obj array"); - ObjArrayKlass_OOP_ITERATE( \ - objArrayOop(obj), p, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }) -} - -int ObjArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - assert (obj->is_objArray(), "obj must be obj array"); - objArrayOop a = objArrayOop(obj); - int size = a->object_size(); - ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p)) - return size; -} -#endif // INCLUDE_ALL_GCS - // JVM support jint ObjArrayKlass::compute_modifier_flags(TRAPS) const { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/objArrayKlass.hpp --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,7 +26,6 @@ #define SHARE_VM_OOPS_OBJARRAYKLASS_HPP #include "classfile/classLoaderData.hpp" -#include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "utilities/macros.hpp" @@ -103,28 +102,67 @@ // Initialization (virtual from Klass) void initialize(TRAPS); - // Garbage collection - void oop_follow_contents(oop obj); - inline void oop_follow_contents(oop obj, int index); - template inline void objarray_follow_contents(oop obj, int index); - - int oop_adjust_pointers(oop obj); - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); #if INCLUDE_ALL_GCS - inline void oop_follow_contents(ParCompactionManager* cm, oop obj, int index); - template inline void - objarray_follow_contents(ParCompactionManager* cm, oop obj, int index); -#endif // INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The ObjArrayKlass iterators also visits the Object's klass. + + private: + + // Iterate over oop elements and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + // Iterate over oop elements within mr, and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over oop elements with indices within [start, end), and metadata. + template + inline int oop_oop_iterate_range(oop obj, OopClosureType* closure, int start, int end); - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Iterate over oop elements within [start, end), and metadata. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_range_specialized(objArrayOop a, OopClosureType* closure, int start, int end); + + public: + // Iterate over all oop elements. + template + inline void oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure); + + private: + // Iterate over all oop elements. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_elements_specialized(objArrayOop a, OopClosureType* closure); + + // Iterate over all oop elements with indices within mr. + template + inline void oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, MemRegion mr); + + // Iterate over oop elements within [low, high).. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_elements_specialized_bounded(objArrayOop a, OopClosureType* closure, void* low, void* high); + + + public: + #define ObjArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, \ @@ -135,6 +173,14 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DECL) +#if INCLUDE_ALL_GCS +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // INCLUDE_ALL_GCS + // JVM support jint compute_modifier_flags(TRAPS) const; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/objArrayKlass.inline.hpp --- a/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,78 +25,165 @@ #ifndef SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP #define SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP -#include "gc_implementation/shared/markSweep.inline.hpp" +#include "memory/memRegion.hpp" +#include "memory/iterator.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif // INCLUDE_ALL_GCS + +template +void ObjArrayKlass::oop_oop_iterate_elements_specialized(objArrayOop a, OopClosureType* closure) { + T* p = (T*)a->base(); + T* const end = p + a->length(); + + for (;p < end; p++) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements_specialized_bounded( + objArrayOop a, OopClosureType* closure, void* low, void* high) { + + T* const l = (T*)low; + T* const h = (T*)high; + + T* p = (T*)a->base(); + T* end = p + a->length(); -void ObjArrayKlass::oop_follow_contents(oop obj, int index) { + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure) { if (UseCompressedOops) { - objarray_follow_contents(obj, index); + oop_oop_iterate_elements_specialized(a, closure); } else { - objarray_follow_contents(obj, index); + oop_oop_iterate_elements_specialized(a, closure); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_elements_specialized_bounded(a, closure, mr.start(), mr.end()); + } else { + oop_oop_iterate_elements_specialized_bounded(a, closure, mr.start(), mr.end()); } } -template -void ObjArrayKlass::objarray_follow_contents(oop obj, int index) { +template +int ObjArrayKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + assert (obj->is_array(), "obj must be array"); objArrayOop a = objArrayOop(obj); - const size_t len = size_t(a->length()); - const size_t beg_index = size_t(index); - assert(beg_index < len || len == 0, "index too large"); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call. + int size = a->object_size(); + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, obj->klass()); + } + + oop_oop_iterate_elements(a, closure); - const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); - const size_t end_index = beg_index + stride; - T* const base = (T*)a->base(); - T* const beg = base + beg_index; - T* const end = base + end_index; + return size; +} - // Push the non-NULL elements of the next stride on the marking stack. - for (T* e = beg; e < end; e++) { - MarkSweep::mark_and_push(e); +template +int ObjArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + assert(obj->is_array(), "obj must be array"); + objArrayOop a = objArrayOop(obj); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call + int size = a->object_size(); + + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, a->klass()); } - if (end_index < len) { - MarkSweep::push_objarray(a, end_index); // Push the continuation. + oop_oop_iterate_elements_bounded(a, closure, mr); + + return size; +} + +template +void ObjArrayKlass::oop_oop_iterate_range_specialized(objArrayOop a, OopClosureType* closure, int start, int end) { + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, a->klass()); } + + T* low = start == 0 ? cast_from_oop(a) : a->obj_at_addr(start); + T* high = (T*)a->base() + end; + + oop_oop_iterate_elements_specialized_bounded(a, closure, low, high); +} + +// Like oop_oop_iterate but only iterates over a specified range and only used +// for objArrayOops. +template +int ObjArrayKlass::oop_oop_iterate_range(oop obj, OopClosureType* closure, int start, int end) { + assert(obj->is_array(), "obj must be array"); + objArrayOop a = objArrayOop(obj); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call + int size = a->object_size(); + + if (UseCompressedOops) { + oop_oop_iterate_range_specialized(a, closure, start, end); + } else { + oop_oop_iterate_range_specialized(a, closure, start, end); + } + + return size; +} + + +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ } #if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj, - int index) { - if (UseCompressedOops) { - objarray_follow_contents(cm, obj, index); - } else { - objarray_follow_contents(cm, obj, index); - } +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ +int ObjArrayKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + /* No reverse implementation ATM. */ \ + return oop_oop_iterate(obj, closure); \ +} +#else +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ } -template -void ObjArrayKlass::objarray_follow_contents(ParCompactionManager* cm, oop obj, - int index) { - objArrayOop a = objArrayOop(obj); - const size_t len = size_t(a->length()); - const size_t beg_index = size_t(index); - assert(beg_index < len || len == 0, "index too large"); +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, int start, int end) { \ + return oop_oop_iterate_range(obj, closure, start, end); \ +} + - const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); - const size_t end_index = beg_index + stride; - T* const base = (T*)a->base(); - T* const beg = base + beg_index; - T* const end = base + end_index; +#define ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r( OopClosureType, nv_suffix) - // Push the non-NULL elements of the next stride on the marking stack. - for (T* e = beg; e < end; e++) { - PSParallelCompact::mark_and_push(cm, e); - } - - if (end_index < len) { - cm->push_objarray(a, end_index); // Push the continuation. - } -} -#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/oop.hpp --- a/hotspot/src/share/vm/oops/oop.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/oop.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -298,19 +298,6 @@ // garbage collection bool is_gc_marked() const; - // Apply "MarkSweep::mark_and_push" to (the address of) every non-NULL - // reference field in "this". - void follow_contents(void); - -#if INCLUDE_ALL_GCS - // Parallel Scavenge - void push_contents(PSPromotionManager* pm); - - // Parallel Old - void update_contents(ParCompactionManager* cm); - - void follow_contents(ParCompactionManager* cm); -#endif // INCLUDE_ALL_GCS bool is_scavengable() const; @@ -334,9 +321,6 @@ uint age() const; void incr_age(); - // Adjust all pointers in this object to point at it's forwarded location and - // return the size of this oop. This is used by the MarkSweep collector. - int adjust_pointers(); // mark-sweep support void follow_body(int begin, int end); @@ -345,6 +329,22 @@ static BarrierSet* bs() { return _bs; } static void set_bs(BarrierSet* bs) { _bs = bs; } + // Garbage Collection support + + // Mark Sweep + void ms_follow_contents(); + // Adjust all pointers in this object to point at it's forwarded location and + // return the size of this oop. This is used by the MarkSweep collector. + int ms_adjust_pointers(); +#if INCLUDE_ALL_GCS + // Parallel Compact + void pc_follow_contents(ParCompactionManager* pc); + void pc_update_contents(); + // Parallel Scavenge + void ps_push_contents(PSPromotionManager* pm); +#endif + + // iterators, returns size of object #define OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_iterate(OopClosureType* blk); \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -26,13 +26,11 @@ #define SHARE_VM_OOPS_OOP_INLINE_HPP #include "gc_implementation/shared/ageTable.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/barrierSet.inline.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/generation.hpp" -#include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" #include "oops/klass.inline.hpp" @@ -592,11 +590,6 @@ } #endif // PRODUCT -inline void oopDesc::follow_contents(void) { - assert (is_gc_marked(), "should be marked"); - klass()->oop_follow_contents(this); -} - inline bool oopDesc::is_scavengable() const { return Universe::heap()->is_scavengable(this); } @@ -706,21 +699,49 @@ } } -inline int oopDesc::adjust_pointers() { +inline void oopDesc::ms_follow_contents() { + klass()->oop_ms_follow_contents(this); +} + +inline int oopDesc::ms_adjust_pointers() { debug_only(int check_size = size()); - int s = klass()->oop_adjust_pointers(this); + int s = klass()->oop_ms_adjust_pointers(this); assert(s == check_size, "should be the same"); return s; } -#define OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -inline int oopDesc::oop_iterate(OopClosureType* blk) { \ - return klass()->oop_oop_iterate##nv_suffix(this, blk); \ -} \ - \ -inline int oopDesc::oop_iterate(OopClosureType* blk, MemRegion mr) { \ - return klass()->oop_oop_iterate##nv_suffix##_m(this, blk, mr); \ +#if INCLUDE_ALL_GCS +inline void oopDesc::pc_follow_contents(ParCompactionManager* cm) { + klass()->oop_pc_follow_contents(this, cm); +} + +inline void oopDesc::pc_update_contents() { + Klass* k = klass(); + if (!k->oop_is_typeArray()) { + // It might contain oops beyond the header, so take the virtual call. + k->oop_pc_update_pointers(this); + } + // Else skip it. The TypeArrayKlass in the header never needs scavenging. +} + +inline void oopDesc::ps_push_contents(PSPromotionManager* pm) { + Klass* k = klass(); + if (!k->oop_is_typeArray()) { + // It might contain oops beyond the header, so take the virtual call. + k->oop_ps_push_contents(this, pm); + } + // Else skip it. The TypeArrayKlass in the header never needs scavenging. +} +#endif + +#define OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +inline int oopDesc::oop_iterate(OopClosureType* blk) { \ + return klass()->oop_oop_iterate##nv_suffix(this, blk); \ +} \ + \ +inline int oopDesc::oop_iterate(OopClosureType* blk, MemRegion mr) { \ + return klass()->oop_oop_iterate##nv_suffix##_m(this, blk, mr); \ } @@ -736,18 +757,21 @@ return oop_iterate(&cl, mr); } -ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DEFN) +#if INCLUDE_ALL_GCS +#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ + return klass()->oop_oop_iterate_backwards##nv_suffix(this, blk); \ +} +#else +#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif -#if INCLUDE_ALL_GCS -#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ - return klass()->oop_oop_iterate_backwards##nv_suffix(this, blk); \ -} +#define ALL_OOPDESC_OOP_ITERATE(OopClosureType, nv_suffix) \ + OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) -ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS +ALL_OOP_OOP_ITERATE_CLOSURES_1(ALL_OOPDESC_OOP_ITERATE) +ALL_OOP_OOP_ITERATE_CLOSURES_2(ALL_OOPDESC_OOP_ITERATE) #endif // SHARE_VM_OOPS_OOP_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/oop.pcgc.inline.hpp --- a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP -#define SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP - -#include "runtime/atomic.inline.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parNew/parNewGeneration.hpp" -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif // INCLUDE_ALL_GCS - -inline void oopDesc::update_contents(ParCompactionManager* cm) { - // The klass field must be updated before anything else - // can be done. - DEBUG_ONLY(Klass* original_klass = klass()); - - Klass* new_klass = klass(); - if (!new_klass->oop_is_typeArray()) { - // It might contain oops beyond the header, so take the virtual call. - new_klass->oop_update_pointers(cm, this); - } - // Else skip it. The TypeArrayKlass in the header never needs scavenging. -} - -inline void oopDesc::follow_contents(ParCompactionManager* cm) { - assert (PSParallelCompact::mark_bitmap()->is_marked(this), - "should be marked"); - klass()->oop_follow_contents(cm, this); -} - -#endif // SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/oop.psgc.inline.hpp --- a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP -#define SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP - -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif // INCLUDE_ALL_GCS - -// ParallelScavengeHeap methods - -inline void oopDesc::push_contents(PSPromotionManager* pm) { - Klass* k = klass(); - if (!k->oop_is_typeArray()) { - // It might contain oops beyond the header, so take the virtual call. - k->oop_push_contents(pm, this); - } - // Else skip it. The TypeArrayKlass in the header never needs scavenging. -} - -#endif // SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/typeArrayKlass.cpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -36,7 +36,7 @@ #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" -#include "oops/typeArrayKlass.hpp" +#include "oops/typeArrayKlass.inline.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/handles.inline.hpp" #include "runtime/orderAccess.inline.hpp" @@ -204,57 +204,6 @@ return t->object_size(); } -void TypeArrayKlass::oop_follow_contents(oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. -} - -#if INCLUDE_ALL_GCS -void TypeArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. -} -#endif // INCLUDE_ALL_GCS - -int TypeArrayKlass::oop_adjust_pointers(oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -int TypeArrayKlass::oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -int TypeArrayKlass::oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -#if INCLUDE_ALL_GCS -void TypeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - ShouldNotReachHere(); - assert(obj->is_typeArray(),"must be a type array"); -} - -int -TypeArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - return typeArrayOop(obj)->object_size(); -} -#endif // INCLUDE_ALL_GCS - void TypeArrayKlass::initialize(TRAPS) { // Nothing to do. Having this function is handy since objArrayKlasses can be // initialized by calling initialize on their bottom_klass, see ObjArrayKlass::initialize diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/typeArrayKlass.hpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -72,16 +72,46 @@ // Copying void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); - // Iteration - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk); - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop iterators. Since there are no oops in TypeArrayKlasses, + // these functions only return the size of the object. + + private: + // The implementation used by all oop_oop_iterate functions in TypeArrayKlasses. + inline int oop_oop_iterate_impl(oop obj, ExtendedOopClosure* closure); - // Garbage collection - void oop_follow_contents(oop obj); - int oop_adjust_pointers(oop obj); + public: + +#define TypeArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, \ + MemRegion mr); \ + int oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, \ + int start, int end); - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_DECL) + +#if INCLUDE_ALL_GCS +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // INCLUDE_ALL_GCS + protected: // Find n'th dimensional array diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP +#define SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP + +#include "oops/oop.inline.hpp" +#include "oops/typeArrayKlass.hpp" +#include "oops/typeArrayOop.hpp" + +class ExtendedOopClosure; + +inline int TypeArrayKlass::oop_oop_iterate_impl(oop obj, ExtendedOopClosure* closure) { + assert(obj->is_typeArray(),"must be a type array"); + typeArrayOop t = typeArrayOop(obj); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. + return t->object_size(); +} + +#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_impl(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_impl(obj, closure); \ +} +#else +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_impl(obj, closure); \ +} + +#define ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/c2_globals.hpp --- a/hotspot/src/share/vm/opto/c2_globals.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/c2_globals.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -324,6 +324,9 @@ develop(bool, SuperWordRTDepCheck, false, \ "Enable runtime dependency checks.") \ \ + product(bool, SuperWordReductions, true, \ + "Enable reductions support in superword.") \ + \ notproduct(bool, TraceSuperWord, false, \ "Trace superword transforms") \ \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/callGenerator.cpp --- a/hotspot/src/share/vm/opto/callGenerator.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/callGenerator.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -876,7 +876,8 @@ // Parse::do_call()) target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass, target, receiver_type, is_virtual, - call_does_dispatch, vtable_index); // out-parameters + call_does_dispatch, vtable_index, // out-parameters + /*check_access=*/false); // We lack profiling at this call but type speculation may // provide us with a type speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/castnode.cpp --- a/hotspot/src/share/vm/opto/castnode.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/castnode.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -216,16 +216,13 @@ const Type *result = _type; if( in_type != NULL && my_type != NULL ) { TypePtr::PTR in_ptr = in_type->ptr(); - if( in_ptr == TypePtr::Null ) { + if (in_ptr == TypePtr::Null) { result = in_type; - } else if( in_ptr == TypePtr::Constant ) { - // Casting a constant oop to an interface? - // (i.e., a String to a Comparable?) - // Then return the interface. + } else if (in_ptr == TypePtr::Constant) { const TypeOopPtr *jptr = my_type->isa_oopptr(); - assert( jptr, "" ); - result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) - ? my_type->cast_to_ptr_type( TypePtr::NotNull ) + assert(jptr, ""); + result = !in_type->higher_equal(_type) + ? my_type->cast_to_ptr_type(TypePtr::NotNull) : in_type; } else { result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -525,13 +525,16 @@ // Cut the backedge input and remove phis since no data paths left. // We don't cut outputs to other nodes here since we need to put them // on the worklist. + PhaseIterGVN *igvn = phase->is_IterGVN(); + if (in(1)->outcnt() == 1) { + igvn->_worklist.push(in(1)); + } del_req(1); cnt = 0; assert( req() == 1, "no more inputs expected" ); uint max = outcnt(); bool progress = true; Node *top = phase->C->top(); - PhaseIterGVN *igvn = phase->is_IterGVN(); DUIterator j; while(progress) { progress = false; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/cfgnode.hpp --- a/hotspot/src/share/vm/opto/cfgnode.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/cfgnode.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -263,6 +263,30 @@ // Size is bigger to hold the probability field. However, _prob does not // change the semantics so it does not appear in the hash & cmp functions. virtual uint size_of() const { return sizeof(*this); } + +private: + ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); + ProjNode* range_check_trap_proj() { + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + return range_check_trap_proj(flip_test, l, r); + } + + // Helper methods for fold_compares + bool cmpi_folds(PhaseIterGVN* igvn); + bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn); + bool has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail); + bool has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn); + static void merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + static void improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn); + bool is_cmp_with_loadrange(ProjNode* proj); + bool is_null_check(ProjNode* proj, PhaseIterGVN* igvn); + bool is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn); + void reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn); + ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call) const; + bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + public: // Degrees of branch prediction probability by order of magnitude: @@ -348,7 +372,7 @@ virtual const RegMask &out_RegMask() const; void dominated_by(Node* prev_dom, PhaseIterGVN* igvn); int is_range_check(Node* &range, Node* &index, jint &offset); - Node* fold_compares(PhaseGVN* phase); + Node* fold_compares(PhaseIterGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); // Takes the type of val and filters it through the test represented diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/classes.hpp --- a/hotspot/src/share/vm/opto/classes.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/classes.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -266,9 +266,13 @@ macro(AddVB) macro(AddVS) macro(AddVI) +macro(AddReductionVI) macro(AddVL) +macro(AddReductionVL) macro(AddVF) +macro(AddReductionVF) macro(AddVD) +macro(AddReductionVD) macro(SubVB) macro(SubVS) macro(SubVI) @@ -277,8 +281,11 @@ macro(SubVD) macro(MulVS) macro(MulVI) +macro(MulReductionVI) macro(MulVF) +macro(MulReductionVF) macro(MulVD) +macro(MulReductionVD) macro(DivVF) macro(DivVD) macro(LShiftCntV) diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/compile.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -3049,6 +3049,15 @@ case Op_StoreVector: break; + case Op_AddReductionVI: + case Op_AddReductionVL: + case Op_AddReductionVF: + case Op_AddReductionVD: + case Op_MulReductionVI: + case Op_MulReductionVF: + case Op_MulReductionVD: + break; + case Op_PackB: case Op_PackS: case Op_PackI: diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/compile.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -879,9 +879,11 @@ ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool &call_does_dispatch, int &vtable_index); + bool &call_does_dispatch, int &vtable_index, + bool check_access = true); ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type); + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access = true); // Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/doCall.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -959,13 +959,15 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool& call_does_dispatch, int& vtable_index) { + bool& call_does_dispatch, int& vtable_index, + bool check_access) { // Set default values for out-parameters. call_does_dispatch = true; vtable_index = Method::invalid_vtable_index; // Choose call strategy. - ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, receiver_type); + ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, + receiver_type, check_access); // Have the call been sufficiently improved such that it is no longer a virtual? if (optimized_virtual_method != NULL) { @@ -980,7 +982,8 @@ // Identify possible target method and inlining style ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type) { + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access) { // only use for virtual or interface calls // If it is obviously final, do not bother to call find_monomorphic_target, @@ -1020,7 +1023,7 @@ } ciInstanceKlass* calling_klass = caller->holder(); - ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver); + ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver, check_access); if (cha_monomorphic_target != NULL) { assert(!cha_monomorphic_target->is_abstract(), ""); // Look at the method-receiver type. Does it add "too much information"? diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -2530,6 +2530,11 @@ // prior to coming here. Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn) { Compile* C = gvn->C; + + if ((*ctrl)->is_top()) { + return C->top(); + } + // Fast check for identical types, perhaps identical constants. // The types can even be identical non-constants, in cases // involving Array.newInstance, Object.clone, etc. @@ -2792,18 +2797,19 @@ */ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, ciKlass* type, - bool not_null, - SafePointNode* sfpt) { + bool not_null) { + if (stopped()) { + return obj; + } + // type == NULL if profiling tells us this object is always null if (type != NULL) { Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; Deoptimization::DeoptReason null_reason = Deoptimization::Reason_speculate_null_check; - ciMethod* trap_method = (sfpt == NULL) ? method() : sfpt->jvms()->method(); - int trap_bci = (sfpt == NULL) ? bci() : sfpt->jvms()->bci(); if (!too_many_traps(null_reason) && !too_many_recompiles(null_reason) && - !C->too_many_traps(trap_method, trap_bci, class_reason) && - !C->too_many_recompiles(trap_method, trap_bci, class_reason)) { + !too_many_traps(class_reason) && + !too_many_recompiles(class_reason)) { Node* not_null_obj = NULL; // not_null is true if we know the object is not null and // there's no need for a null check @@ -2819,12 +2825,7 @@ ciKlass* exact_kls = type; Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0, &exact_obj); - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - PreserveJVMState pjvms(&kit); - kit.set_control(slow_ctl); - kit.uncommon_trap_exact(class_reason, Deoptimization::Action_maybe_recompile); - } else { + { PreserveJVMState pjvms(this); set_control(slow_ctl); uncommon_trap_exact(class_reason, Deoptimization::Action_maybe_recompile); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -409,8 +409,7 @@ // Cast obj to type and emit guard unless we had too many traps here already Node* maybe_cast_profiled_obj(Node* obj, ciKlass* type, - bool not_null = false, - SafePointNode* sfpt = NULL); + bool not_null = false); // Cast obj to not-null on this path Node* cast_not_null(Node* obj, bool do_replace_in_map = true); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -25,11 +25,13 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/phaseX.hpp" #include "opto/runtime.hpp" +#include "opto/rootnode.hpp" #include "opto/subnode.hpp" // Portions of code courtesy of Clifford Click @@ -449,62 +451,59 @@ return new ConINode(TypeInt::ZERO); } -//------------------------------is_range_check--------------------------------- -// Return 0 if not a range check. Return 1 if a range check and set index and -// offset. Return 2 if we had to negate the test. Index is NULL if the check -// is versus a constant. -int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { +// if this IfNode follows a range check pattern return the projection +// for the failed path +ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { Node* b = in(1); - if (b == NULL || !b->is_Bool()) return 0; + if (b == NULL || !b->is_Bool()) return NULL; BoolNode* bn = b->as_Bool(); Node* cmp = bn->in(1); - if (cmp == NULL) return 0; - if (cmp->Opcode() != Op_CmpU) return 0; + if (cmp == NULL) return NULL; + if (cmp->Opcode() != Op_CmpU) return NULL; - Node* l = cmp->in(1); - Node* r = cmp->in(2); - int flip_test = 1; + l = cmp->in(1); + r = cmp->in(2); + flip_test = 1; if (bn->_test._test == BoolTest::le) { l = cmp->in(2); r = cmp->in(1); flip_test = 2; } else if (bn->_test._test != BoolTest::lt) { - return 0; + return NULL; } - if (l->is_top()) return 0; // Top input means dead test - if (r->Opcode() != Op_LoadRange) return 0; + if (l->is_top()) return NULL; // Top input means dead test + if (r->Opcode() != Op_LoadRange) return NULL; // We have recognized one of these forms: // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... + ProjNode* iftrap = proj_out(flip_test == 2 ? true : false); + return iftrap; +} + + +//------------------------------is_range_check--------------------------------- +// Return 0 if not a range check. Return 1 if a range check and set index and +// offset. Return 2 if we had to negate the test. Index is NULL if the check +// is versus a constant. +int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + ProjNode* iftrap = range_check_trap_proj(flip_test, l, r); + + if (iftrap == NULL) { + return 0; + } + // Make sure it's a real range check by requiring an uncommon trap // along the OOB path. Otherwise, it's possible that the user wrote // something which optimized to look like a range check but behaves // in some other way. - Node* iftrap = proj_out(flip_test == 2 ? true : false); - bool found_trap = false; - if (iftrap != NULL) { - Node* u = iftrap->unique_ctrl_out(); - if (u != NULL) { - // It could be a merge point (Region) for uncommon trap. - if (u->is_Region()) { - Node* c = u->unique_ctrl_out(); - if (c != NULL) { - iftrap = u; - u = c; - } - } - if (u->in(0) == iftrap && u->is_CallStaticJava()) { - int req = u->as_CallStaticJava()->uncommon_trap_request(); - if (Deoptimization::trap_request_reason(req) == - Deoptimization::Reason_range_check) { - found_trap = true; - } - } - } + if (iftrap->is_uncommon_trap_proj(Deoptimization::Reason_range_check) == NULL) { + return 0; } - if (!found_trap) return 0; // sorry, no cigar // Look for index+offset form Node* ind = l; @@ -664,11 +663,12 @@ //------------------------------fold_compares---------------------------- // See if a pair of CmpIs can be converted into a CmpU. In some cases // the direction of this if is determined by the preceding if so it -// can be eliminate entirely. Given an if testing (CmpI n c) check -// for an immediately control dependent if that is testing (CmpI n c2) -// and has one projection leading to this if and the other projection -// leading to a region that merges one of this ifs control -// projections. +// can be eliminate entirely. +// +// Given an if testing (CmpI n v) check for an immediately control +// dependent if that is testing (CmpI n v2) and has one projection +// leading to this if and the other projection leading to a region +// that merges one of this ifs control projections. // // If // / | @@ -680,79 +680,458 @@ // / \ | // / Region // -Node* IfNode::fold_compares(PhaseGVN* phase) { - if (Opcode() != Op_If) return NULL; +// Or given an if testing (CmpI n v) check for a dominating if that is +// testing (CmpI n v2), both having one projection leading to an +// uncommon trap. Allow Another independent guard in between to cover +// an explicit range check: +// if (index < 0 || index >= array.length) { +// which may need a null check to guard the LoadRange +// +// If +// / \ +// / \ +// / \ +// If unc +// /\ +// / \ +// / \ +// / unc +// + +// Is the comparison for this If suitable for folding? +bool IfNode::cmpi_folds(PhaseIterGVN* igvn) { + return in(1) != NULL && + in(1)->is_Bool() && + in(1)->in(1) != NULL && + in(1)->in(1)->Opcode() == Op_CmpI && + in(1)->in(1)->in(2) != NULL && + in(1)->in(1)->in(2) != igvn->C->top() && + (in(1)->as_Bool()->_test.is_less() || + in(1)->as_Bool()->_test.is_greater()); +} + +// Is a dominating control suitable for folding with this if? +bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) { + return ctrl != NULL && + ctrl->is_Proj() && + ctrl->in(0) != NULL && + ctrl->in(0)->is_If() && + ctrl->in(0)->outcnt() == 2 && + ctrl->in(0)->as_If()->cmpi_folds(igvn) && + // Must compare same value + ctrl->in(0)->in(1)->in(1)->in(1) != NULL && + ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1); +} + +// Do this If and the dominating If share a region? +bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail) { + ProjNode* otherproj = proj->other_if_proj(); + Node* otherproj_ctrl_use = otherproj->unique_ctrl_out(); + RegionNode* region = (otherproj_ctrl_use != NULL && otherproj_ctrl_use->is_Region()) ? otherproj_ctrl_use->as_Region() : NULL; + success = NULL; + fail = NULL; + if (otherproj->outcnt() == 1 && region != NULL && !region->has_phi()) { + for (int i = 0; i < 2; i++) { + ProjNode* proj = proj_out(i); + if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { + success = proj; + } else if (fail == NULL) { + fail = proj; + } else { + success = fail = NULL; + } + } + } + return success != NULL && fail != NULL; +} + +// Return projection that leads to an uncommon trap if any +ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { + for (int i = 0; i < 2; i++) { + call = proj_out(i)->is_uncommon_trap_proj(Deoptimization::Reason_none); + if (call != NULL) { + return proj_out(i); + } + } + return NULL; +} + +// Do this If and the dominating If both branch out to an uncommon trap +bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) { + ProjNode* otherproj = proj->other_if_proj(); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + + if (otherproj->outcnt() == 1 && dom_unc != NULL) { + CallStaticJavaNode* unc = NULL; + ProjNode* unc_proj = uncommon_trap_proj(unc); + if (unc_proj != NULL && unc_proj->outcnt() == 1) { + if (dom_unc == unc) { + // Allow the uncommon trap to be shared through a region + RegionNode* r = unc->in(0)->as_Region(); + if (r->outcnt() != 2 || r->req() != 3 || r->find_edge(otherproj) == -1 || r->find_edge(unc_proj) == -1) { + return false; + } + assert(r->has_phi() == NULL, "simple region shouldn't have a phi"); + } else if (dom_unc->in(0) != otherproj || unc->in(0) != unc_proj) { + return false; + } + // See merge_uncommon_traps: the reason of the uncommon trap + // will be changed and the state of the dominating If will be + // used. Checked that we didn't apply this transformation in a + // previous compilation and it didn't cause too many traps + if (!igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_unstable_fused_if) && + !igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_range_check)) { + success = unc_proj; + fail = unc_proj->other_if_proj(); + return true; + } + } + } + return false; +} + +// Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding +bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { Node* this_cmp = in(1)->in(1); - if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI && - this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) { - Node* ctrl = in(0); - BoolNode* this_bool = in(1)->as_Bool(); - Node* n = this_cmp->in(1); - int hi = this_cmp->in(2)->get_int(); - if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 && - ctrl->in(0)->is_If() && - ctrl->in(0)->outcnt() == 2 && - ctrl->in(0)->in(1)->is_Bool() && - ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI && - ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() && - ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() && - ctrl->in(0)->in(1)->in(1)->in(1) == n) { - IfNode* dom_iff = ctrl->in(0)->as_If(); - Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con); - if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() && - this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) { - // Identify which proj goes to the region and which continues on - RegionNode* region = otherproj->unique_out()->as_Region(); - Node* success = NULL; - Node* fail = NULL; - for (int i = 0; i < 2; i++) { - Node* proj = proj_out(i); - if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { - success = proj; - } else if (fail == NULL) { - fail = proj; - } else { - success = fail = NULL; + BoolNode* this_bool = in(1)->as_Bool(); + IfNode* dom_iff = proj->in(0)->as_If(); + BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); + Node* lo = dom_iff->in(1)->in(1)->in(2); + Node* hi = this_cmp->in(2); + Node* n = this_cmp->in(1); + ProjNode* otherproj = proj->other_if_proj(); + + const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj); + const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success); + + BoolTest::mask lo_test = dom_bool->_test._test; + BoolTest::mask hi_test = this_bool->_test._test; + BoolTest::mask cond = hi_test; + + // Figure out which of the two tests sets the upper bound and which + // sets the lower bound if any. + if (hi_type->_lo > lo_type->_hi && hi_type->_hi == max_jint && lo_type->_lo == min_jint) { + + assert((dom_bool->_test.is_less() && !proj->_con) || + (dom_bool->_test.is_greater() && proj->_con), "incorrect test"); + // this test was canonicalized + assert(this_bool->_test.is_less() && fail->_con, "incorrect test"); + + if (lo_test == BoolTest::gt || lo_test == BoolTest::le) { + lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); + } + } else if (lo_type->_lo > hi_type->_hi && lo_type->_hi == max_jint && hi_type->_lo == min_jint) { + swap(lo, hi); + swap(lo_type, hi_type); + swap(lo_test, hi_test); + + assert((this_bool->_test.is_less() && proj->_con) || + (this_bool->_test.is_greater() && !proj->_con), "incorrect test"); + // this test was canonicalized + assert(dom_bool->_test.is_less() && !fail->_con, "incorrect test"); + + cond = (hi_test == BoolTest::le || hi_test == BoolTest::gt) ? BoolTest::gt : BoolTest::ge; + + if (lo_test == BoolTest::le) { + lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); + } + + } else { + const TypeInt* failtype = filtered_int_type(igvn, n, proj); + if (failtype != NULL) { + const TypeInt* type2 = filtered_int_type(igvn, n, fail); + if (type2 != NULL) { + failtype = failtype->join(type2)->is_int(); + if (failtype->_lo > failtype->_hi) { + // previous if determines the result of this if so + // replace Bool with constant + igvn->hash_delete(this); + set_req(1, igvn->intcon(success->_con)); + return true; + } + } + } + + lo = NULL; + hi = NULL; + } + + if (lo && hi) { + // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo)) + Node* adjusted_val = igvn->transform(new SubINode(n, lo)); + Node* adjusted_lim = igvn->transform(new SubINode(hi, lo)); + Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim)); + Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); + + igvn->is_IterGVN()->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); + igvn->hash_delete(this); + set_req(1, newbool); + + return true; + } + return false; +} + +// Merge the branches that trap for this If and the dominating If into +// a single region that branches to the uncommon trap for the +// dominating If +void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { + ProjNode* otherproj = proj->other_if_proj(); + + CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + + if (unc != dom_unc) { + Node* r = new RegionNode(3); + + r->set_req(1, otherproj); + r->set_req(2, success); + r = igvn->transform(r); + assert(r->is_Region(), "can't go away"); + + // Make both If trap at the state of the first If: once the CmpI + // nodes are merged, if we trap we don't know which of the CmpI + // nodes would have caused the trap so we have to restart + // execution at the first one + igvn->replace_input_of(dom_unc, 0, r); + igvn->replace_input_of(unc, 0, igvn->C->top()); + } + int trap_request = dom_unc->uncommon_trap_request(); + Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); + Deoptimization::DeoptAction action = Deoptimization::trap_request_action(trap_request); + + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + + if (success->in(0)->as_If()->range_check_trap_proj(flip_test, l, r) != NULL) { + // If this looks like a range check, change the trap to + // Reason_range_check so the compiler recognizes it as a range + // check and applies the corresponding optimizations + trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_range_check, action); + + improve_address_types(l, r, fail, igvn); + } else if (unc != dom_unc) { + // If we trap we won't know what CmpI would have caused the trap + // so use a special trap reason to mark this pair of CmpI nodes as + // bad candidate for folding. On recompilation we won't fold them + // and we may trap again but this time we'll know what branch + // traps + trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_unstable_fused_if, action); + } + igvn->replace_input_of(dom_unc, TypeFunc::Parms, igvn->intcon(trap_request)); +} + +// If we are turning 2 CmpI nodes into a CmpU that follows the pattern +// of a rangecheck on index i, on 64 bit the compares may be followed +// by memory accesses using i as index. In that case, the CmpU tells +// us something about the values taken by i that can help the compiler +// (see Compile::conv_I2X_index()) +void IfNode::improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn) { +#ifdef _LP64 + ResourceMark rm; + Node_Stack stack(2); + + assert(r->Opcode() == Op_LoadRange, "unexpected range check"); + const TypeInt* array_size = igvn->type(r)->is_int(); + + stack.push(l, 0); + + while(stack.size() > 0) { + Node* n = stack.node(); + uint start = stack.index(); + + uint i = start; + for (; i < n->outcnt(); i++) { + Node* use = n->raw_out(i); + if (stack.size() == 1) { + if (use->Opcode() == Op_ConvI2L) { + const TypeLong* bounds = use->as_Type()->type()->is_long(); + if (bounds->_lo <= array_size->_lo && bounds->_hi >= array_size->_hi && + (bounds->_lo != array_size->_lo || bounds->_hi != array_size->_hi)) { + stack.set_index(i+1); + stack.push(use, 0); + break; } } - if (success != NULL && fail != NULL && !region->has_phi()) { - int lo = dom_iff->in(1)->in(1)->in(2)->get_int(); - BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); - Node* dom_cmp = dom_bool->in(1); - const TypeInt* failtype = filtered_int_type(phase, n, ctrl); - if (failtype != NULL) { - const TypeInt* type2 = filtered_int_type(phase, n, fail); - if (type2 != NULL) { - failtype = failtype->join(type2)->is_int(); - } else { - failtype = NULL; - } - } + } else if (use->is_Mem()) { + Node* ctrl = use->in(0); + for (int i = 0; i < 10 && ctrl != NULL && ctrl != fail; i++) { + ctrl = up_one_dom(ctrl); + } + if (ctrl == fail) { + Node* init_n = stack.node_at(1); + assert(init_n->Opcode() == Op_ConvI2L, "unexpected first node"); + Node* new_n = igvn->C->conv_I2X_index(igvn, l, array_size); - if (failtype != NULL && - dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) { - int bound = failtype->_hi - failtype->_lo + 1; - if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) { - // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi) - BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge; - Node* adjusted = phase->transform(new SubINode(n, phase->intcon(failtype->_lo))); - Node* newcmp = phase->transform(new CmpUNode(adjusted, phase->intcon(bound))); - Node* newbool = phase->transform(new BoolNode(newcmp, cond)); - phase->is_IterGVN()->replace_input_of(dom_iff, 1, phase->intcon(ctrl->as_Proj()->_con)); - phase->hash_delete(this); - set_req(1, newbool); - return this; - } - if (failtype->_lo > failtype->_hi) { - // previous if determines the result of this if so - // replace Bool with constant - phase->hash_delete(this); - set_req(1, phase->intcon(success->as_Proj()->_con)); - return this; - } + for (uint j = 2; j < stack.size(); j++) { + Node* n = stack.node_at(j); + Node* clone = n->clone(); + int rep = clone->replace_edge(init_n, new_n); + assert(rep > 0, "can't find expected node?"); + clone = igvn->transform(clone); + init_n = n; + new_n = clone; + } + igvn->hash_delete(use); + int rep = use->replace_edge(init_n, new_n); + assert(rep > 0, "can't find expected node?"); + igvn->transform(use); + if (init_n->outcnt() == 0) { + igvn->_worklist.push(init_n); } } + } else if (use->in(0) == NULL && (igvn->type(use)->isa_long() || + igvn->type(use)->isa_ptr())) { + stack.set_index(i+1); + stack.push(use, 0); + break; + } + } + if (i == n->outcnt()) { + stack.pop(); + } + } +#endif +} + +bool IfNode::is_cmp_with_loadrange(ProjNode* proj) { + if (in(1) != NULL && + in(1)->in(1) != NULL && + in(1)->in(1)->in(2) != NULL) { + Node* other = in(1)->in(1)->in(2); + if (other->Opcode() == Op_LoadRange && + ((other->in(0) != NULL && other->in(0) == proj) || + (other->in(0) == NULL && + other->in(2) != NULL && + other->in(2)->is_AddP() && + other->in(2)->in(1) != NULL && + other->in(2)->in(1)->Opcode() == Op_CastPP && + other->in(2)->in(1)->in(0) == proj))) { + return true; + } + } + return false; +} + +bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) { + Node* other = in(1)->in(1)->in(2); + if (other->in(MemNode::Address) != NULL && + proj->in(0)->in(1) != NULL && + proj->in(0)->in(1)->is_Bool() && + proj->in(0)->in(1)->in(1) != NULL && + proj->in(0)->in(1)->in(1)->Opcode() == Op_CmpP && + proj->in(0)->in(1)->in(1)->in(2) != NULL && + proj->in(0)->in(1)->in(1)->in(1) == other->in(MemNode::Address)->in(AddPNode::Address)->uncast() && + igvn->type(proj->in(0)->in(1)->in(1)->in(2)) == TypePtr::NULL_PTR) { + return true; + } + return false; +} + +// Check that the If that is in between the 2 integer comparisons has +// no side effect +bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { + if (proj != NULL && + proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + proj->outcnt() <= 2) { + if (proj->outcnt() == 1 || + // Allow simple null check from LoadRange + (is_cmp_with_loadrange(proj) && is_null_check(proj, igvn))) { + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + + // reroute_side_effect_free_unc changes the state of this + // uncommon trap to restart execution at the previous + // CmpI. Check that this change in a previous compilation didn't + // cause too many traps. + int trap_request = unc->uncommon_trap_request(); + Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); + + if (igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), reason)) { + return false; + } + + return true; + } + } + return false; +} + +// Make the If between the 2 integer comparisons trap at the state of +// the first If: the last CmpI is the one replaced by a CmpU and the +// first CmpI is eliminated, so the test between the 2 CmpI nodes +// won't be guarded by the first CmpI anymore. It can trap in cases +// where the first CmpI would have prevented it from executing: on a +// trap, we need to restart execution at the state of the first CmpI +void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) { + CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + ProjNode* otherproj = proj->other_if_proj(); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + Node* call_proj = dom_unc->unique_ctrl_out(); + Node* halt = call_proj->unique_ctrl_out(); + + Node* new_unc = dom_unc->clone(); + call_proj = call_proj->clone(); + halt = halt->clone(); + Node* c = otherproj->clone(); + + c = igvn->transform(c); + new_unc->set_req(TypeFunc::Parms, unc->in(TypeFunc::Parms)); + new_unc->set_req(0, c); + new_unc = igvn->transform(new_unc); + call_proj->set_req(0, new_unc); + call_proj = igvn->transform(call_proj); + halt->set_req(0, call_proj); + halt = igvn->transform(halt); + + igvn->replace_node(otherproj, igvn->C->top()); + igvn->C->root()->add_req(halt); +} + +Node* IfNode::fold_compares(PhaseIterGVN* igvn) { + if (Opcode() != Op_If) return NULL; + + if (cmpi_folds(igvn)) { + Node* ctrl = in(0); + if (is_ctrl_folds(ctrl, igvn) && + ctrl->outcnt() == 1) { + // A integer comparison immediately dominated by another integer + // comparison + ProjNode* success = NULL; + ProjNode* fail = NULL; + ProjNode* dom_cmp = ctrl->as_Proj(); + if (has_shared_region(dom_cmp, success, fail) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + return this; + } + if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + merge_uncommon_traps(dom_cmp, success, fail, igvn); + return this; + } + return NULL; + } else if (ctrl->in(0) != NULL && + ctrl->in(0)->in(0) != NULL) { + ProjNode* success = NULL; + ProjNode* fail = NULL; + Node* dom = ctrl->in(0)->in(0); + ProjNode* dom_cmp = dom->isa_Proj(); + ProjNode* other_cmp = ctrl->isa_Proj(); + + // Check if it's an integer comparison dominated by another + // integer comparison with another test in between + if (is_ctrl_folds(dom, igvn) && + has_only_uncommon_traps(dom_cmp, success, fail, igvn) && + is_side_effect_free_test(other_cmp, igvn) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn); + merge_uncommon_traps(dom_cmp, success, fail, igvn); + return this; } } } @@ -1029,7 +1408,7 @@ // Normal equivalent-test check. if( !dom ) return NULL; // Dead loop? - Node* result = fold_compares(phase); + Node* result = fold_compares(igvn); if (result != NULL) { return result; } @@ -1089,7 +1468,7 @@ // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) + if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) prev_dom = idom; // Now walk the current IfNode's projections. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -262,6 +262,9 @@ bool inline_arraycopy(); AllocateArrayNode* tightly_coupled_allocation(Node* ptr, RegionNode* slow_region); + JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); + void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); + typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); bool inline_unsafe_ordered_store(BasicType type); @@ -290,6 +293,7 @@ bool inline_multiplyToLen(); bool inline_profileBoolean(); + bool inline_isCompileConstant(); }; @@ -549,6 +553,17 @@ if (!Matcher::match_rule_supported(Op_OverflowMulL) || !UseMathExactIntrinsics) return NULL; break; + case vmIntrinsics::_getShortUnaligned: + case vmIntrinsics::_getCharUnaligned: + case vmIntrinsics::_getIntUnaligned: + case vmIntrinsics::_getLongUnaligned: + case vmIntrinsics::_putShortUnaligned: + case vmIntrinsics::_putCharUnaligned: + case vmIntrinsics::_putIntUnaligned: + case vmIntrinsics::_putLongUnaligned: + if (!UseUnalignedAccesses) return NULL; + break; + default: assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); @@ -799,6 +814,16 @@ case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile); case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); + + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile); + case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmpxchg); @@ -900,6 +925,8 @@ case vmIntrinsics::_profileBoolean: return inline_profileBoolean(); + case vmIntrinsics::_isCompileConstant: + return inline_isCompileConstant(); default: // If you get here, it may be that someone has added a new intrinsic @@ -3664,6 +3691,11 @@ //---------------------generate_array_guard_common------------------------ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region, bool obj_array, bool not_array) { + + if (stopped()) { + return NULL; + } + // If obj_array/non_array==false/false: // Branch around if the given klass is in fact an array (either obj or prim). // If obj_array/non_array==false/true: @@ -3911,21 +3943,23 @@ validated = true; } - newcopy = new_array(klass_node, length, 0); // no arguments to push - - ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, - load_object_klass(original), klass_node); - if (!is_copyOfRange) { - ac->set_copyof(validated); - } else { - ac->set_copyofrange(validated); - } - Node* n = _gvn.transform(ac); - if (n == ac) { - ac->connect_outputs(this); - } else { - assert(validated, "shouldn't transform if all arguments not validated"); - set_all_memory(n); + if (!stopped()) { + newcopy = new_array(klass_node, length, 0); // no arguments to push + + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, + load_object_klass(original), klass_node); + if (!is_copyOfRange) { + ac->set_copyof(validated); + } else { + ac->set_copyofrange(validated); + } + Node* n = _gvn.transform(ac); + if (n == ac) { + ac->connect_outputs(this); + } else { + assert(validated, "shouldn't transform if all arguments not validated"); + set_all_memory(n); + } } } } // original reexecute is set back here @@ -4674,6 +4708,141 @@ return true; } +// If we have a tighly coupled allocation, the arraycopy may take care +// of the array initialization. If one of the guards we insert between +// the allocation and the arraycopy causes a deoptimization, an +// unitialized array will escape the compiled method. To prevent that +// we set the JVM state for uncommon traps between the allocation and +// the arraycopy to the state before the allocation so, in case of +// deoptimization, we'll reexecute the allocation and the +// initialization. +JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp) { + if (alloc != NULL) { + ciMethod* trap_method = alloc->jvms()->method(); + int trap_bci = alloc->jvms()->bci(); + + if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) & + !C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_null_check)) { + // Make sure there's no store between the allocation and the + // arraycopy otherwise visible side effects could be rexecuted + // in case of deoptimization and cause incorrect execution. + bool no_interfering_store = true; + Node* mem = alloc->in(TypeFunc::Memory); + if (mem->is_MergeMem()) { + for (MergeMemStream mms(merged_memory(), mem->as_MergeMem()); mms.next_non_empty2(); ) { + Node* n = mms.memory(); + if (n != mms.memory2() && !(n->is_Proj() && n->in(0) == alloc->initialization())) { + assert(n->is_Store(), "what else?"); + no_interfering_store = false; + break; + } + } + } else { + for (MergeMemStream mms(merged_memory()); mms.next_non_empty(); ) { + Node* n = mms.memory(); + if (n != mem && !(n->is_Proj() && n->in(0) == alloc->initialization())) { + assert(n->is_Store(), "what else?"); + no_interfering_store = false; + break; + } + } + } + + if (no_interfering_store) { + JVMState* old_jvms = alloc->jvms()->clone_shallow(C); + uint size = alloc->req(); + SafePointNode* sfpt = new SafePointNode(size, old_jvms); + old_jvms->set_map(sfpt); + for (uint i = 0; i < size; i++) { + sfpt->init_req(i, alloc->in(i)); + } + // re-push array length for deoptimization + sfpt->ins_req(old_jvms->stkoff() + old_jvms->sp(), alloc->in(AllocateNode::ALength)); + old_jvms->set_sp(old_jvms->sp()+1); + old_jvms->set_monoff(old_jvms->monoff()+1); + old_jvms->set_scloff(old_jvms->scloff()+1); + old_jvms->set_endoff(old_jvms->endoff()+1); + old_jvms->set_should_reexecute(true); + + sfpt->set_i_o(map()->i_o()); + sfpt->set_memory(map()->memory()); + sfpt->set_control(map()->control()); + + JVMState* saved_jvms = jvms(); + saved_reexecute_sp = _reexecute_sp; + + set_jvms(sfpt->jvms()); + _reexecute_sp = jvms()->sp(); + + return saved_jvms; + } + } + } + return NULL; +} + +// In case of a deoptimization, we restart execution at the +// allocation, allocating a new array. We would leave an uninitialized +// array in the heap that GCs wouldn't expect. Move the allocation +// after the traps so we don't allocate the array if we +// deoptimize. This is possible because tightly_coupled_allocation() +// guarantees there's no observer of the allocated array at this point +// and the control flow is simple enough. +void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp) { + if (saved_jvms != NULL && !stopped()) { + assert(alloc != NULL, "only with a tightly coupled allocation"); + // restore JVM state to the state at the arraycopy + saved_jvms->map()->set_control(map()->control()); + assert(saved_jvms->map()->memory() == map()->memory(), "memory state changed?"); + assert(saved_jvms->map()->i_o() == map()->i_o(), "IO state changed?"); + // If we've improved the types of some nodes (null check) while + // emitting the guards, propagate them to the current state + map()->replaced_nodes().apply(saved_jvms->map()); + set_jvms(saved_jvms); + _reexecute_sp = saved_reexecute_sp; + + // Remove the allocation from above the guards + CallProjections callprojs; + alloc->extract_projections(&callprojs, true); + InitializeNode* init = alloc->initialization(); + Node* alloc_mem = alloc->in(TypeFunc::Memory); + C->gvn_replace_by(callprojs.fallthrough_ioproj, alloc->in(TypeFunc::I_O)); + C->gvn_replace_by(init->proj_out(TypeFunc::Memory), alloc_mem); + C->gvn_replace_by(init->proj_out(TypeFunc::Control), alloc->in(0)); + + // move the allocation here (after the guards) + _gvn.hash_delete(alloc); + alloc->set_req(TypeFunc::Control, control()); + alloc->set_req(TypeFunc::I_O, i_o()); + Node *mem = reset_memory(); + set_all_memory(mem); + alloc->set_req(TypeFunc::Memory, mem); + set_control(init->proj_out(TypeFunc::Control)); + set_i_o(callprojs.fallthrough_ioproj); + + // Update memory as done in GraphKit::set_output_for_allocation() + const TypeInt* length_type = _gvn.find_int_type(alloc->in(AllocateNode::ALength)); + const TypeOopPtr* ary_type = _gvn.type(alloc->in(AllocateNode::KlassNode))->is_klassptr()->as_instance_type(); + if (ary_type->isa_aryptr() && length_type != NULL) { + ary_type = ary_type->is_aryptr()->cast_to_size(length_type); + } + const TypePtr* telemref = ary_type->add_offset(Type::OffsetBot); + int elemidx = C->get_alias_index(telemref); + set_memory(init->proj_out(TypeFunc::Memory), Compile::AliasIdxRaw); + set_memory(init->proj_out(TypeFunc::Memory), elemidx); + + Node* allocx = _gvn.transform(alloc); + assert(allocx == alloc, "where has the allocation gone?"); + assert(dest->is_CheckCastPP(), "not an allocation result?"); + + _gvn.hash_delete(dest); + dest->set_req(0, control()); + Node* destx = _gvn.transform(dest); + assert(destx == dest, "where has the allocation result gone?"); + } +} + + //------------------------------inline_arraycopy----------------------- // public static native void java.lang.System.arraycopy(Object src, int srcPos, // Object dest, int destPos, @@ -4686,6 +4855,19 @@ Node* dest_offset = argument(3); // type: int Node* length = argument(4); // type: int + + // Check for allocation before we add nodes that would confuse + // tightly_coupled_allocation() + AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL); + + int saved_reexecute_sp = -1; + JVMState* saved_jvms = arraycopy_restore_alloc_state(alloc, saved_reexecute_sp); + // See arraycopy_restore_alloc_state() comment + // if alloc == NULL we don't have to worry about a tightly coupled allocation so we can emit all needed guards + // if saved_jvms != NULL (then alloc != NULL) then we can handle guards and a tightly coupled allocation + // if saved_jvms == NULL and alloc != NULL, we can’t emit any guards + bool can_emit_guards = (alloc == NULL || saved_jvms != NULL); + // The following tests must be performed // (1) src and dest are arrays. // (2) src and dest arrays must have elements of the same BasicType @@ -4699,42 +4881,20 @@ // (3) src and dest must not be null. // always do this here because we need the JVM state for uncommon traps - src = null_check(src, T_ARRAY); + Node* null_ctl = top(); + src = saved_jvms != NULL ? null_check_oop(src, &null_ctl, true, true) : null_check(src, T_ARRAY); + assert(null_ctl->is_top(), "no null control here"); dest = null_check(dest, T_ARRAY); - // Check for allocation before we add nodes that would confuse - // tightly_coupled_allocation() - AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL); - - ciMethod* trap_method = method(); - int trap_bci = bci(); - SafePointNode* sfpt = NULL; - if (alloc != NULL) { - // The JVM state for uncommon traps between the allocation and - // arraycopy is set to the state before the allocation: if the - // initialization is performed by the array copy, we don't want to - // go back to the interpreter with an unitialized array. - JVMState* old_jvms = alloc->jvms(); - JVMState* jvms = old_jvms->clone_shallow(C); - uint size = alloc->req(); - sfpt = new SafePointNode(size, jvms); - jvms->set_map(sfpt); - for (uint i = 0; i < size; i++) { - sfpt->init_req(i, alloc->in(i)); - } - // re-push array length for deoptimization - sfpt->ins_req(jvms->stkoff() + jvms->sp(), alloc->in(AllocateNode::ALength)); - jvms->set_sp(jvms->sp()+1); - jvms->set_monoff(jvms->monoff()+1); - jvms->set_scloff(jvms->scloff()+1); - jvms->set_endoff(jvms->endoff()+1); - jvms->set_should_reexecute(true); - - sfpt->set_i_o(map()->i_o()); - sfpt->set_memory(map()->memory()); - - trap_method = jvms->method(); - trap_bci = jvms->bci(); + if (!can_emit_guards) { + // if saved_jvms == NULL and alloc != NULL, we don't emit any + // guards but the arraycopy node could still take advantage of a + // tightly allocated allocation. tightly_coupled_allocation() is + // called again to make sure it takes the null check above into + // account: the null check is mandatory and if it caused an + // uncommon trap to be emitted then the allocation can't be + // considered tightly coupled in this context. + alloc = tightly_coupled_allocation(dest, NULL); } bool validated = false; @@ -4753,7 +4913,7 @@ // Is the type for dest from speculation? bool dest_spec = false; - if (!has_src || !has_dest) { + if ((!has_src || !has_dest) && can_emit_guards) { // We don't have sufficient type information, let's see if // speculative types can help. We need to have types for both src // and dest so that it pays off. @@ -4782,7 +4942,7 @@ if (could_have_src && could_have_dest) { // This is going to pay off so emit the required guards if (!has_src) { - src = maybe_cast_profiled_obj(src, src_k, true, sfpt); + src = maybe_cast_profiled_obj(src, src_k, true); src_type = _gvn.type(src); top_src = src_type->isa_aryptr(); has_src = (top_src != NULL && top_src->klass() != NULL); @@ -4798,7 +4958,7 @@ } } - if (has_src && has_dest) { + if (has_src && has_dest && can_emit_guards) { BasicType src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); BasicType dest_elem = top_dest->klass()->as_array_klass()->element_type()->basic_type(); if (src_elem == T_ARRAY) src_elem = T_OBJECT; @@ -4830,7 +4990,7 @@ if (could_have_src && could_have_dest) { // If we can have both exact types, emit the missing guards if (could_have_src && !src_spec) { - src = maybe_cast_profiled_obj(src, src_k, true, sfpt); + src = maybe_cast_profiled_obj(src, src_k, true); } if (could_have_dest && !dest_spec) { dest = maybe_cast_profiled_obj(dest, dest_k, true); @@ -4839,7 +4999,16 @@ } } - if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) && !src->is_top() && !dest->is_top()) { + ciMethod* trap_method = method(); + int trap_bci = bci(); + if (saved_jvms != NULL) { + trap_method = alloc->jvms()->method(); + trap_bci = alloc->jvms()->bci(); + } + + if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) && + can_emit_guards && + !src->is_top() && !dest->is_top()) { // validate arguments: enables transformation the ArrayCopyNode validated = true; @@ -4875,28 +5044,13 @@ Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass); if (not_subtype_ctrl != top()) { - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - PreserveJVMState pjvms(&kit); - kit.set_control(not_subtype_ctrl); - kit.uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(kit.stopped(), "Should be stopped"); - } else { - PreserveJVMState pjvms(this); - set_control(not_subtype_ctrl); - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(stopped(), "Should be stopped"); - } + PreserveJVMState pjvms(this); + set_control(not_subtype_ctrl); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + assert(stopped(), "Should be stopped"); } - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - kit.set_control(_gvn.transform(slow_region)); - kit.uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(kit.stopped(), "Should be stopped"); - } else { + { PreserveJVMState pjvms(this); set_control(_gvn.transform(slow_region)); uncommon_trap(Deoptimization::Reason_intrinsic, @@ -4905,6 +5059,8 @@ } } + arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp); + if (stopped()) { return true; } @@ -5870,12 +6026,46 @@ Deoptimization::Action_reinterpret); return true; } + + // result is a boolean (0 or 1) and its profile (false_cnt & true_cnt) + // is a number of each value occurrences. + Node* result = argument(0); + if (false_cnt == 0 || true_cnt == 0) { + // According to profile, one value has been never seen. + int expected_val = (false_cnt == 0) ? 1 : 0; + + Node* cmp = _gvn.transform(new CmpINode(result, intcon(expected_val))); + Node* test = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); + + IfNode* check = create_and_map_if(control(), test, PROB_ALWAYS, COUNT_UNKNOWN); + Node* fast_path = _gvn.transform(new IfTrueNode(check)); + Node* slow_path = _gvn.transform(new IfFalseNode(check)); + + { // Slow path: uncommon trap for never seen value and then reexecute + // MethodHandleImpl::profileBoolean() to bump the count, so JIT knows + // the value has been seen at least once. + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap_exact(Deoptimization::Reason_intrinsic, + Deoptimization::Action_reinterpret); + } + // The guard for never seen value enables sharpening of the result and + // returning a constant. It allows to eliminate branches on the same value + // later on. + set_control(fast_path); + result = intcon(expected_val); + } // Stop profiling. - // MethodHandleImpl::profileBoolean() has profiling logic in it's bytecode. - // By replacing method's body with profile data (represented as ProfileBooleanNode + // MethodHandleImpl::profileBoolean() has profiling logic in its bytecode. + // By replacing method body with profile data (represented as ProfileBooleanNode // on IR level) we effectively disable profiling. // It enables full speed execution once optimized code is generated. - Node* profile = _gvn.transform(new ProfileBooleanNode(argument(0), false_cnt, true_cnt)); + Node* profile = _gvn.transform(new ProfileBooleanNode(result, false_cnt, true_cnt)); C->record_for_igvn(profile); set_result(profile); return true; @@ -5888,3 +6078,9 @@ return false; } } + +bool LibraryCallKit::inline_isCompileConstant() { + Node* n = argument(0); + set_result(n->is_Con() ? intcon(1) : intcon(0)); + return true; +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -38,6 +38,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/vectornode.hpp" //------------------------------is_loop_exit----------------------------------- // Given an IfNode, return the loop-exiting projection or NULL if both @@ -1524,6 +1525,44 @@ } } +void PhaseIdealLoop::mark_reductions(IdealLoopTree *loop) { + if (SuperWordReductions == false) return; + + CountedLoopNode* loop_head = loop->_head->as_CountedLoop(); + if (loop_head->unrolled_count() > 1) { + return; + } + + Node* trip_phi = loop_head->phi(); + for (DUIterator_Fast imax, i = loop_head->fast_outs(imax); i < imax; i++) { + Node* phi = loop_head->fast_out(i); + if (phi->is_Phi() && phi->outcnt() > 0 && phi != trip_phi) { + // For definitions which are loop inclusive and not tripcounts. + Node* def_node = phi->in(LoopNode::LoopBackControl); + + if (def_node != NULL) { + Node* n_ctrl = get_ctrl(def_node); + if (n_ctrl != NULL && loop->is_member(get_loop(n_ctrl))) { + // Now test it to see if it fits the standard pattern for a reduction operator. + int opc = def_node->Opcode(); + if (opc != ReductionNode::opcode(opc, def_node->bottom_type()->basic_type())) { + if (!def_node->is_reduction()) { // Not marked yet + // To be a reduction, the arithmetic node must have the phi as input and provide a def to it + for (unsigned j = 1; j < def_node->req(); j++) { + Node* in = def_node->in(j); + if (in == phi) { + def_node->add_flag(Node::Flag_is_reduction); + break; + } + } + } + } + } + } + } + } +} + //------------------------------dominates_backedge--------------------------------- // Returns true if ctrl is executed on every complete iteration bool IdealLoopTree::dominates_backedge(Node* ctrl) { @@ -2361,8 +2400,10 @@ // an even number of trips). If we are peeling, we might enable some RCE // and we'd rather unroll the post-RCE'd loop SO... do not unroll if // peeling. - if (should_unroll && !should_peel) - phase->do_unroll(this,old_new, true); + if (should_unroll && !should_peel) { + phase->mark_reductions(this); + phase->do_unroll(this, old_new, true); + } // Adjust the pre-loop limits to align the main body // iterations. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -872,6 +872,9 @@ // Unroll the loop body one step - make each trip do 2 iterations. void do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ); + // Mark vector reduction candidates before loop unrolling + void mark_reductions( IdealLoopTree *loop ); + // Return true if exp is a constant times an induction var bool is_scaled_iv(Node* exp, Node* iv, int* p_scale); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -241,8 +241,8 @@ ProjNode* dp_proj = dp->as_Proj(); ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj(); if (exclude_loop_predicate && - (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check))) { + (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL || + unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check) != NULL)) { // If this is a range check (IfNode::is_range_check), do not // reorder because Compile::allow_range_check_smearing might have // changed the check. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/macro.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -2543,7 +2543,7 @@ (bol->_test._test == BoolTest::ne), ""); IfNode* ifn = bol->unique_out()->as_If(); assert((ifn->outcnt() == 2) && - ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change), ""); + ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change) != NULL, ""); #endif Node* repl = n->in(1); if (!_has_locks) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/multnode.cpp --- a/hotspot/src/share/vm/opto/multnode.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/multnode.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -150,59 +150,67 @@ } //-------------------------------is_uncommon_trap_proj---------------------------- -// Return true if proj is the form of "proj->[region->..]call_uct" -bool ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { +// Return uncommon trap call node if proj is for "proj->[region->..]call_uct" +// NULL otherwise +CallStaticJavaNode* ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { int path_limit = 10; Node* out = this; for (int ct = 0; ct < path_limit; ct++) { out = out->unique_ctrl_out(); if (out == NULL) - return false; + return NULL; if (out->is_CallStaticJava()) { - int req = out->as_CallStaticJava()->uncommon_trap_request(); + CallStaticJavaNode* call = out->as_CallStaticJava(); + int req = call->uncommon_trap_request(); if (req != 0) { Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); if (trap_reason == reason || reason == Deoptimization::Reason_none) { - return true; + return call; } } - return false; // don't do further after call + return NULL; // don't do further after call } if (out->Opcode() != Op_Region) - return false; + return NULL; } - return false; + return NULL; } //-------------------------------is_uncommon_trap_if_pattern------------------------- -// Return true for "if(test)-> proj -> ... -// | -// V -// other_proj->[region->..]call_uct" -// +// Return uncommon trap call node for "if(test)-> proj -> ... +// | +// V +// other_proj->[region->..]call_uct" +// NULL otherwise // "must_reason_predicate" means the uct reason must be Reason_predicate -bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { +CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { Node *in0 = in(0); - if (!in0->is_If()) return false; + if (!in0->is_If()) return NULL; // Variation of a dead If node. - if (in0->outcnt() < 2) return false; + if (in0->outcnt() < 2) return NULL; IfNode* iff = in0->as_If(); // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate if (reason != Deoptimization::Reason_none) { if (iff->in(1)->Opcode() != Op_Conv2B || iff->in(1)->in(1)->Opcode() != Op_Opaque1) { - return false; + return NULL; } } ProjNode* other_proj = iff->proj_out(1-_con); if (other_proj == NULL) // Should never happen, but make Parfait happy. - return false; - if (other_proj->is_uncommon_trap_proj(reason)) { + return NULL; + CallStaticJavaNode* call = other_proj->is_uncommon_trap_proj(reason); + if (call != NULL) { assert(reason == Deoptimization::Reason_none || Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); - return true; + return call; } - return false; + return NULL; } + +ProjNode* ProjNode::other_if_proj() const { + assert(_con == 0 || _con == 1, "not an if?"); + return in(0)->as_If()->proj_out(1-_con); +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/multnode.hpp --- a/hotspot/src/share/vm/opto/multnode.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/multnode.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -89,13 +89,18 @@ virtual void dump_spec(outputStream *st) const; #endif - // Return true if proj is for "proj->[region->..]call_uct" - bool is_uncommon_trap_proj(Deoptimization::DeoptReason reason); - // Return true for "if(test)-> proj -> ... - // | - // V - // other_proj->[region->..]call_uct" - bool is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); + // Return uncommon trap call node if proj is for "proj->[region->..]call_uct" + // NULL otherwise + CallStaticJavaNode* is_uncommon_trap_proj(Deoptimization::DeoptReason reason); + // Return uncommon trap call node for "if(test)-> proj -> ... + // | + // V + // other_proj->[region->..]call_uct" + // NULL otherwise + CallStaticJavaNode* is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); + + // Return other proj node when this is a If proj node + ProjNode* other_if_proj() const; }; #endif // SHARE_VM_OPTO_MULTNODE_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/node.cpp --- a/hotspot/src/share/vm/opto/node.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/node.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -2069,7 +2069,7 @@ //--------------------------unique_ctrl_out------------------------------ // Return the unique control out if only one. Null if none or more than one. -Node* Node::unique_ctrl_out() { +Node* Node::unique_ctrl_out() const { Node* found = NULL; for (uint i = 0; i < outcnt(); i++) { Node* use = raw_out(i); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/node.hpp --- a/hotspot/src/share/vm/opto/node.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/node.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -673,7 +673,8 @@ Flag_avoid_back_to_back_before = Flag_may_be_short_branch << 1, Flag_avoid_back_to_back_after = Flag_avoid_back_to_back_before << 1, Flag_has_call = Flag_avoid_back_to_back_after << 1, - Flag_is_expensive = Flag_has_call << 1, + Flag_is_reduction = Flag_has_call << 1, + Flag_is_expensive = Flag_is_reduction << 1, _max_flags = (Flag_is_expensive << 1) - 1 // allow flags combination }; @@ -701,6 +702,10 @@ const jushort flags() const { return _flags; } + void add_flag(jushort fl) { init_flags(fl); } + + void remove_flag(jushort fl) { clear_flag(fl); } + // Return a dense integer opcode number virtual int Opcode() const; @@ -852,6 +857,10 @@ // The node is expensive: the best control is set during loop opts bool is_expensive() const { return (_flags & Flag_is_expensive) != 0 && in(0) != NULL; } + // An arithmetic node which accumulates a data in a loop. + // It must have the loop's phi as input and provide a def to the phi. + bool is_reduction() const { return (_flags & Flag_is_reduction) != 0; } + //----------------- Optimization // Get the worst-case Type output for this Node. @@ -931,7 +940,7 @@ Node* find_similar(int opc); // Return the unique control out if only one. Null if none or more than one. - Node* unique_ctrl_out(); + Node* unique_ctrl_out() const; //----------------- Code Generation diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/subnode.hpp --- a/hotspot/src/share/vm/opto/subnode.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/subnode.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -275,6 +275,8 @@ mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } + bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; } + bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; } void dump_on(outputStream *st) const; }; diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/superword.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -65,7 +65,8 @@ _lpt(NULL), // loop tree node _lp(NULL), // LoopNode _bb(NULL), // basic block - _iv(NULL) // induction var + _iv(NULL), // induction var + _race_possible(false) // cases where SDMU is true {} //------------------------------transform_loop--------------------------- @@ -145,7 +146,6 @@ void SuperWord::SLP_extract() { // Ready the block - if (!construct_bb()) return; // Exit if no interesting nodes or complex graph. @@ -449,11 +449,13 @@ int preloop_stride = pre_end->stride_con(); int span = preloop_stride * p.scale_in_bytes(); - - // Stride one accesses are alignable. - if (ABS(span) == p.memory_size()) + int mem_size = p.memory_size(); + int offset = p.offset_in_bytes(); + // Stride one accesses are alignable if offset is aligned to memory operation size. + // Offset can be unaligned when UseUnalignedAccesses is used. + if (ABS(span) == mem_size && (ABS(offset) % mem_size) == 0) { return true; - + } // If initial offset from start of object is computable, // compute alignment within the vector. int vw = vector_width_in_bytes(p.mem()); @@ -463,7 +465,7 @@ if (init_nd->is_Con() && p.invar() == NULL) { int init = init_nd->bottom_type()->is_int()->get_con(); - int init_offset = init * p.scale_in_bytes() + p.offset_in_bytes(); + int init_offset = init * p.scale_in_bytes() + offset; assert(init_offset >= 0, "positive offset from object start"); if (span > 0) { @@ -640,7 +642,7 @@ } if (isomorphic(s1, s2)) { - if (independent(s1, s2)) { + if (independent(s1, s2) || reduction(s1, s2)) { if (!exists_at(s1, 0) && !exists_at(s2, 1)) { if (!s1->is_Mem() || are_adjacent_refs(s1, s2)) { int s1_align = alignment(s1); @@ -718,6 +720,28 @@ return independent_path(shallow, deep); } +//------------------------------reduction--------------------------- +// Is there a data path between s1 and s2 and the nodes reductions? +bool SuperWord::reduction(Node* s1, Node* s2) { + bool retValue = false; + int d1 = depth(s1); + int d2 = depth(s2); + if (d1 + 1 == d2) { + if (s1->is_reduction() && s2->is_reduction()) { + // This is an ordered set, so s1 should define s2 + for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { + Node* t1 = s1->fast_out(i); + if (t1 == s2) { + // both nodes are reductions and connected + retValue = true; + } + } + } + } + + return retValue; +} + //------------------------------independent_path------------------------------ // Helper for independent bool SuperWord::independent_path(Node* shallow, Node* deep, uint dp) { @@ -761,6 +785,7 @@ void SuperWord::extend_packlist() { bool changed; do { + packset_sort(_packset.length()); changed = false; for (int i = 0; i < _packset.length(); i++) { Node_List* p = _packset.at(i); @@ -769,6 +794,13 @@ } } while (changed); + if (_race_possible) { + for (int i = 0; i < _packset.length(); i++) { + Node_List* p = _packset.at(i); + order_def_uses(p); + } + } + #ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nAfter extend_packlist"); @@ -825,10 +857,12 @@ int align = alignment(s1); int savings = -1; + int num_s1_uses = 0; Node* u1 = NULL; Node* u2 = NULL; for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { Node* t1 = s1->fast_out(i); + num_s1_uses++; if (!in_bb(t1)) continue; for (DUIterator_Fast jmax, j = s2->fast_outs(jmax); j < jmax; j++) { Node* t2 = s2->fast_out(j); @@ -845,6 +879,9 @@ } } } + if (num_s1_uses > 1) { + _race_possible = true; + } if (savings >= 0) { Node_List* pair = new Node_List(); pair->push(u1); @@ -856,9 +893,64 @@ return changed; } +//------------------------------order_def_uses--------------------------- +// For extended packsets, ordinally arrange uses packset by major component +void SuperWord::order_def_uses(Node_List* p) { + Node* s1 = p->at(0); + + if (s1->is_Store()) return; + + // reductions are always managed beforehand + if (s1->is_reduction()) return; + + for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { + Node* t1 = s1->fast_out(i); + + // Only allow operand swap on commuting operations + if (!t1->is_Add() && !t1->is_Mul()) { + break; + } + + // Now find t1's packset + Node_List* p2 = NULL; + for (int j = 0; j < _packset.length(); j++) { + p2 = _packset.at(j); + Node* first = p2->at(0); + if (t1 == first) { + break; + } + p2 = NULL; + } + // Arrange all sub components by the major component + if (p2 != NULL) { + for (uint j = 1; j < p->size(); j++) { + Node* d1 = p->at(j); + Node* u1 = p2->at(j); + opnd_positions_match(s1, t1, d1, u1); + } + } + } +} + //---------------------------opnd_positions_match------------------------- // Is the use of d1 in u1 at the same operand position as d2 in u2? bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) { + // check reductions to see if they are marshalled to represent the reduction + // operator in a specified opnd + if (u1->is_reduction() && u2->is_reduction()) { + // ensure reductions have phis and reduction definitions feeding the 1st operand + Node* first = u1->in(2); + if (first->is_Phi() || first->is_reduction()) { + u1->swap_edges(1, 2); + } + // ensure reductions have phis and reduction definitions feeding the 1st operand + first = u2->in(2); + if (first->is_Phi() || first->is_reduction()) { + u2->swap_edges(1, 2); + } + return true; + } + uint ct = u1->req(); if (ct != u2->req()) return false; uint i1 = 0; @@ -940,7 +1032,8 @@ for (int i = 0; i < _packset.length(); i++) { Node_List* p1 = _packset.at(i); if (p1 == NULL) continue; - for (int j = 0; j < _packset.length(); j++) { + // Because of sorting we can start at i + 1 + for (int j = i + 1; j < _packset.length(); j++) { Node_List* p2 = _packset.at(j); if (p2 == NULL) continue; if (i == j) continue; @@ -1067,8 +1160,19 @@ //------------------------------implemented--------------------------- // Can code be generated for pack p? bool SuperWord::implemented(Node_List* p) { + bool retValue = false; Node* p0 = p->at(0); - return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0)); + if (p0 != NULL) { + int opc = p0->Opcode(); + uint size = p->size(); + if (p0->is_reduction()) { + const Type *arith_type = p0->bottom_type(); + retValue = ReductionNode::implemented(opc, size, arith_type->basic_type()); + } else { + retValue = VectorNode::implemented(opc, size, velt_basic_type(p0)); + } + } + return retValue; } //------------------------------same_inputs-------------------------- @@ -1102,6 +1206,18 @@ if (!is_vector_use(p0, i)) return false; } + // Check if reductions are connected + if (p0->is_reduction()) { + Node* second_in = p0->in(2); + Node_List* second_pk = my_pack(second_in); + if (second_pk == NULL) { + // Remove reduction flag if no parent pack, it is not profitable + p0->remove_flag(Node::Flag_is_reduction); + return false; + } else if (second_pk->size() != p->size()) { + return false; + } + } if (VectorNode::is_shift(p0)) { // For now, return false if shift count is vector or not scalar promotion // case (different shift counts) because it is not supported yet. @@ -1123,6 +1239,9 @@ for (uint k = 0; k < use->req(); k++) { Node* n = use->in(k); if (def == n) { + // reductions can be loop carried dependences + if (def->is_reduction() && use->is_Phi()) + continue; if (!is_vector_use(use, k)) { return false; } @@ -1407,16 +1526,33 @@ vlen_in_bytes = vn->as_StoreVector()->memory_size(); } else if (n->req() == 3) { // Promote operands to vector - Node* in1 = vector_opd(p, 1); + Node* in1 = NULL; + bool node_isa_reduction = n->is_reduction(); + if (node_isa_reduction) { + // the input to the first reduction operation is retained + in1 = low_adr->in(1); + } else { + in1 = vector_opd(p, 1); + } Node* in2 = vector_opd(p, 2); - if (VectorNode::is_invariant_vector(in1) && (n->is_Add() || n->is_Mul())) { + if (VectorNode::is_invariant_vector(in1) && (node_isa_reduction == false) && (n->is_Add() || n->is_Mul())) { // Move invariant vector input into second position to avoid register spilling. Node* tmp = in1; in1 = in2; in2 = tmp; } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); + if (node_isa_reduction) { + const Type *arith_type = n->bottom_type(); + vn = ReductionNode::make(opc, NULL, in1, in2, arith_type->basic_type()); + if (in2->is_Load()) { + vlen_in_bytes = in2->as_LoadVector()->memory_size(); + } else { + vlen_in_bytes = in2->as_Vector()->length_in_bytes(); + } + } else { + vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); + vlen_in_bytes = vn->as_Vector()->length_in_bytes(); + } } else { ShouldNotReachHere(); } @@ -1556,6 +1692,8 @@ _n_idx_list.pop(); Node* def = use->in(idx); + if (def->is_reduction()) continue; + // Insert extract operation _igvn.hash_delete(def); int def_pos = alignment(def) / data_size(def); @@ -1576,6 +1714,7 @@ bool SuperWord::is_vector_use(Node* use, int u_idx) { Node_List* u_pk = my_pack(use); if (u_pk == NULL) return false; + if (use->is_reduction()) return true; Node* def = use->in(u_idx); Node_List* d_pk = my_pack(def); if (d_pk == NULL) { @@ -1613,7 +1752,7 @@ // by the visited and post_visited sets, // and count number of nodes in block. int bb_ct = 0; - for (uint i = 0; i < lpt()->_body.size(); i++ ) { + for (uint i = 0; i < lpt()->_body.size(); i++) { Node *n = lpt()->_body.at(i); set_bb_idx(n, i); // Create a temporary map if (in_bb(n)) { @@ -1674,6 +1813,7 @@ // Do a depth first walk over out edges int rpo_idx = bb_ct - 1; int size; + int reduction_uses = 0; while ((size = _stk.length()) > 0) { Node* n = _stk.top(); // Leave node on stack if (!visited_test_set(n)) { @@ -1685,6 +1825,14 @@ if (in_bb(use) && !visited_test(use) && // Don't go around backedge (!use->is_Phi() || n == entry)) { + if (use->is_reduction()) { + // First see if we can map the reduction on the given system we are on, then + // make a data entry operation for each reduction we see. + BasicType bt = use->bottom_type()->basic_type(); + if (ReductionNode::implemented(use->Opcode(), Matcher::min_vector_size(bt), bt)) { + reduction_uses++; + } + } _stk.push(use); } } @@ -1708,7 +1856,8 @@ set_bb_idx(n, j); } - initialize_bb(); // Ensure extra info is allocated. + // Ensure extra info is allocated. + initialize_bb(); #ifndef PRODUCT if (TraceSuperWord) { @@ -1726,7 +1875,7 @@ } #endif assert(rpo_idx == -1 && bb_ct == _block.length(), "all block members found"); - return (_mem_slice_head.length() > 0) || (_data_entry.length() > 0); + return (_mem_slice_head.length() > 0) || (reduction_uses > 0) || (_data_entry.length() > 0); } //------------------------------initialize_bb--------------------------- @@ -1959,6 +2108,27 @@ _packset.remove_at(pos); } +void SuperWord::packset_sort(int n) { + // simple bubble sort so that we capitalize with O(n) when its already sorted + while (n != 0) { + bool swapped = false; + for (int i = 1; i < n; i++) { + Node_List* q_low = _packset.at(i-1); + Node_List* q_i = _packset.at(i); + + // only swap when we find something to swap + if (alignment(q_low->at(0)) > alignment(q_i->at(0))) { + Node_List* t = q_i; + *(_packset.adr_at(i)) = q_low; + *(_packset.adr_at(i-1)) = q_i; + swapped = true; + } + } + if (swapped == false) break; + n--; + } +} + //------------------------------executed_first--------------------------- // Return the node executed first in pack p. Uses the RPO block list // to determine order. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/superword.hpp --- a/hotspot/src/share/vm/opto/superword.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/superword.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -249,6 +249,7 @@ LoopNode* _lp; // Current LoopNode Node* _bb; // Current basic block PhiNode* _iv; // Induction var + bool _race_possible; // In cases where SDMU is true // Accessors Arena* arena() { return _arena; } @@ -337,6 +338,8 @@ bool isomorphic(Node* s1, Node* s2); // Is there no data path from s1 to s2 or s2 to s1? bool independent(Node* s1, Node* s2); + // Is there a data path between s1 and s2 and both are reductions? + bool reduction(Node* s1, Node* s2); // Helper for independent bool independent_path(Node* shallow, Node* deep, uint dp=0); void set_alignment(Node* s1, Node* s2, int align); @@ -347,6 +350,8 @@ bool follow_use_defs(Node_List* p); // Extend the packset by visiting uses of nodes in pack p bool follow_def_uses(Node_List* p); + // For extended packsets, ordinally arrange uses packset by major component + void order_def_uses(Node_List* p); // Estimate the savings from executing s1 and s2 as a pack int est_savings(Node* s1, Node* s2); int adjacent_profit(Node* s1, Node* s2); @@ -419,9 +424,12 @@ void print_bb(); void print_stmt(Node* s); char* blank(uint depth); + + void packset_sort(int n); }; + //------------------------------SWPointer--------------------------- // Information about an address for dependence checking and vector alignment class SWPointer VALUE_OBJ_CLASS_SPEC { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/type.cpp --- a/hotspot/src/share/vm/opto/type.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/type.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -4083,7 +4083,9 @@ (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { - tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + if (above_centerline(ptr)) { + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + } return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/vectornode.cpp --- a/hotspot/src/share/vm/opto/vectornode.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/vectornode.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -250,7 +250,6 @@ int vopc = VectorNode::opcode(opc, bt); // This method should not be called for unimplemented vectors. guarantee(vopc > 0, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); - switch (vopc) { case Op_AddVB: return new AddVBNode(n1, n2, vt); case Op_AddVS: return new AddVSNode(n1, n2, vt); @@ -441,3 +440,72 @@ return NULL; } +int ReductionNode::opcode(int opc, BasicType bt) { + int vopc = opc; + switch (opc) { + case Op_AddI: + assert(bt == T_INT, "must be"); + vopc = Op_AddReductionVI; + break; + case Op_AddL: + assert(bt == T_LONG, "must be"); + vopc = Op_AddReductionVL; + break; + case Op_AddF: + assert(bt == T_FLOAT, "must be"); + vopc = Op_AddReductionVF; + break; + case Op_AddD: + assert(bt == T_DOUBLE, "must be"); + vopc = Op_AddReductionVD; + break; + case Op_MulI: + assert(bt == T_INT, "must be"); + vopc = Op_MulReductionVI; + break; + case Op_MulF: + assert(bt == T_FLOAT, "must be"); + vopc = Op_MulReductionVF; + break; + case Op_MulD: + assert(bt == T_DOUBLE, "must be"); + vopc = Op_MulReductionVD; + break; + // TODO: add MulL for targets that support it + default: + break; + } + return vopc; +} + +// Return the appropriate reduction node. +ReductionNode* ReductionNode::make(int opc, Node *ctrl, Node* n1, Node* n2, BasicType bt) { + + int vopc = opcode(opc, bt); + + // This method should not be called for unimplemented vectors. + guarantee(vopc != opc, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + + switch (vopc) { + case Op_AddReductionVI: return new AddReductionVINode(ctrl, n1, n2); + case Op_AddReductionVL: return new AddReductionVLNode(ctrl, n1, n2); + case Op_AddReductionVF: return new AddReductionVFNode(ctrl, n1, n2); + case Op_AddReductionVD: return new AddReductionVDNode(ctrl, n1, n2); + case Op_MulReductionVI: return new MulReductionVINode(ctrl, n1, n2); + case Op_MulReductionVF: return new MulReductionVFNode(ctrl, n1, n2); + case Op_MulReductionVD: return new MulReductionVDNode(ctrl, n1, n2); + } + fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + return NULL; +} + +bool ReductionNode::implemented(int opc, uint vlen, BasicType bt) { + if (is_java_primitive(bt) && + (vlen > 1) && is_power_of_2(vlen) && + Matcher::vector_size_supported(bt, vlen)) { + int vopc = ReductionNode::opcode(opc, bt); + return vopc != opc && Matcher::match_rule_supported(vopc); + } + return false; +} + diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -90,6 +90,37 @@ virtual int Opcode() const; }; +//------------------------------ReductionNode------------------------------------ +// Perform reduction of a vector +class ReductionNode : public Node { + public: + ReductionNode(Node *ctrl, Node* in1, Node* in2) : Node(ctrl, in1, in2) {} + + static ReductionNode* make(int opc, Node *ctrl, Node* in1, Node* in2, BasicType bt); + static int opcode(int opc, BasicType bt); + static bool implemented(int opc, uint vlen, BasicType bt); +}; + +//------------------------------AddReductionVINode-------------------------------------- +// Vector add int as a reduction +class AddReductionVINode : public ReductionNode { +public: + AddReductionVINode(Node * ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------AddReductionVLNode-------------------------------------- +// Vector add long as a reduction +class AddReductionVLNode : public ReductionNode { +public: + AddReductionVLNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeLong::LONG; } + virtual uint ideal_reg() const { return Op_RegL; } +}; + //------------------------------AddVLNode-------------------------------------- // Vector add long class AddVLNode : public VectorNode { @@ -106,6 +137,16 @@ virtual int Opcode() const; }; +//------------------------------AddReductionVFNode-------------------------------------- +// Vector add float as a reduction +class AddReductionVFNode : public ReductionNode { +public: + AddReductionVFNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } +}; + //------------------------------AddVDNode-------------------------------------- // Vector add double class AddVDNode : public VectorNode { @@ -114,6 +155,16 @@ virtual int Opcode() const; }; +//------------------------------AddReductionVDNode-------------------------------------- +// Vector add double as a reduction +class AddReductionVDNode : public ReductionNode { +public: + AddReductionVDNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } +}; + //------------------------------SubVBNode-------------------------------------- // Vector subtract byte class SubVBNode : public VectorNode { @@ -178,6 +229,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVINode-------------------------------------- +// Vector multiply int as a reduction +class MulReductionVINode : public ReductionNode { +public: + MulReductionVINode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + //------------------------------MulVFNode-------------------------------------- // Vector multiply float class MulVFNode : public VectorNode { @@ -186,6 +247,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVFNode-------------------------------------- +// Vector multiply float as a reduction +class MulReductionVFNode : public ReductionNode { +public: + MulReductionVFNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } +}; + //------------------------------MulVDNode-------------------------------------- // Vector multiply double class MulVDNode : public VectorNode { @@ -194,6 +265,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVDNode-------------------------------------- +// Vector multiply double as a reduction +class MulReductionVDNode : public ReductionNode { +public: + MulReductionVDNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } +}; + //------------------------------DivVFNode-------------------------------------- // Vector divide float class DivVFNode : public VectorNode { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/precompiled/precompiled.hpp --- a/hotspot/src/share/vm/precompiled/precompiled.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -94,7 +94,6 @@ # include "gc_implementation/shared/spaceCounters.hpp" # include "gc_implementation/shared/spaceDecorator.hpp" # include "gc_interface/collectedHeap.hpp" -# include "gc_interface/collectedHeap.inline.hpp" # include "gc_interface/gcCause.hpp" # include "interpreter/abstractInterpreter.hpp" # include "interpreter/bytecode.hpp" @@ -114,15 +113,12 @@ # include "memory/allocation.hpp" # include "memory/allocation.inline.hpp" # include "memory/barrierSet.hpp" -# include "memory/barrierSet.inline.hpp" # include "memory/blockOffsetTable.hpp" -# include "memory/blockOffsetTable.inline.hpp" # include "memory/cardTableModRefBS.hpp" # include "memory/collectorPolicy.hpp" # include "memory/defNewGeneration.hpp" # include "memory/gcLocker.hpp" # include "memory/genCollectedHeap.hpp" -# include "memory/genOopClosures.hpp" # include "memory/genRemSet.hpp" # include "memory/generation.hpp" # include "memory/heap.hpp" @@ -133,10 +129,8 @@ # include "memory/referencePolicy.hpp" # include "memory/referenceProcessor.hpp" # include "memory/resourceArea.hpp" -# include "memory/sharedHeap.hpp" # include "memory/space.hpp" # include "memory/threadLocalAllocBuffer.hpp" -# include "memory/threadLocalAllocBuffer.inline.hpp" # include "memory/universe.hpp" # include "memory/universe.inline.hpp" # include "memory/watermark.hpp" @@ -147,7 +141,6 @@ # include "oops/instanceOop.hpp" # include "oops/instanceRefKlass.hpp" # include "oops/klass.hpp" -# include "oops/klassPS.hpp" # include "oops/klassVtable.hpp" # include "oops/markOop.hpp" # include "oops/markOop.inline.hpp" @@ -305,7 +298,6 @@ # include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" # include "gc_implementation/g1/dirtyCardQueue.hpp" # include "gc_implementation/g1/g1BlockOffsetTable.hpp" -# include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" # include "gc_implementation/g1/g1OopClosures.hpp" # include "gc_implementation/g1/g1_globals.hpp" # include "gc_implementation/g1/ptrQueue.hpp" @@ -319,7 +311,6 @@ # include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" # include "gc_implementation/parallelScavenge/psGenerationCounters.hpp" # include "gc_implementation/parallelScavenge/psOldGen.hpp" -# include "gc_implementation/parallelScavenge/psParallelCompact.hpp" # include "gc_implementation/parallelScavenge/psVirtualspace.hpp" # include "gc_implementation/parallelScavenge/psYoungGen.hpp" # include "gc_implementation/shared/gcAdaptivePolicyCounters.hpp" diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/jvm.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1465,63 +1465,26 @@ } JVM_END -// should be in InstanceKlass.cpp, but is here for historical reasons -Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, - bool* inner_is_member, - TRAPS) { - Thread* thread = THREAD; - InnerClassesIterator iter(k); - if (iter.length() == 0) { - // No inner class info => no declaring class +JVM_ENTRY(jstring, JVM_GetSimpleBinaryName(JNIEnv *env, jclass cls)) +{ + oop mirror = JNIHandles::resolve_non_null(cls); + if (java_lang_Class::is_primitive(mirror) || + !java_lang_Class::as_Klass(mirror)->oop_is_instance()) { return NULL; } - - constantPoolHandle i_cp(thread, k->constants()); - - bool found = false; - Klass* ok; - instanceKlassHandle outer_klass; - *inner_is_member = false; - - // Find inner_klass attribute - for (; !iter.done() && !found; iter.next()) { - int ioff = iter.inner_class_info_index(); - int ooff = iter.outer_class_info_index(); - int noff = iter.inner_name_index(); - if (ioff != 0) { - // Check to see if the name matches the class we're looking for - // before attempting to find the class. - if (i_cp->klass_name_at_matches(k, ioff)) { - Klass* inner_klass = i_cp->klass_at(ioff, CHECK_NULL); - found = (k() == inner_klass); - if (found && ooff != 0) { - ok = i_cp->klass_at(ooff, CHECK_NULL); - outer_klass = instanceKlassHandle(thread, ok); - *inner_is_member = true; - } - } + instanceKlassHandle k(THREAD, InstanceKlass::cast(java_lang_Class::as_Klass(mirror))); + int ooff = 0, noff = 0; + if (InstanceKlass::find_inner_classes_attr(k, &ooff, &noff, THREAD)) { + if (noff != 0) { + constantPoolHandle i_cp(thread, k->constants()); + Symbol* name = i_cp->symbol_at(noff); + Handle str = java_lang_String::create_from_symbol(name, CHECK_NULL); + return (jstring) JNIHandles::make_local(env, str()); } } - - if (found && outer_klass.is_null()) { - // It may be anonymous; try for that. - int encl_method_class_idx = k->enclosing_method_class_index(); - 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; - } - } - - // If no inner class attribute found for this class. - if (outer_klass.is_null()) return NULL; - - // Throws an exception if outer klass has not declared k as an inner klass - // We need evidence that each klass knows about the other, or else - // the system could allow a spoof of an inner class to gain access rights. - Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL); - return outer_klass(); + return NULL; } +JVM_END JVM_ENTRY(jstring, JVM_GetClassSignature(JNIEnv *env, jclass cls)) assert (cls != NULL, "illegal class"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/jvm.h Fri Apr 17 14:37:20 2015 -0700 @@ -426,6 +426,9 @@ JNIEXPORT jclass JNICALL JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass); +JNIEXPORT jstring JNICALL +JVM_GetSimpleBinaryName(JNIEnv *env, jclass ofClass); + /* Generics support (JDK 1.5) */ JNIEXPORT jstring JNICALL JVM_GetClassSignature(JNIEnv *env, jclass cls); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -994,22 +994,8 @@ // that intrinsic (non-JNI) native methods are defined in HotSpot. // -JVM_ENTRY(jint, MHN_getConstant(JNIEnv *env, jobject igcls, jint which)) { - switch (which) { - case MethodHandles::GC_COUNT_GWT: -#ifdef COMPILER2 - return true; -#else - return false; -#endif - } - return 0; -} -JVM_END - #ifndef PRODUCT #define EACH_NAMED_CON(template, requirement) \ - template(MethodHandles,GC_COUNT_GWT) \ template(java_lang_invoke_MemberName,MN_IS_METHOD) \ template(java_lang_invoke_MemberName,MN_IS_CONSTRUCTOR) \ template(java_lang_invoke_MemberName,MN_IS_FIELD) \ @@ -1019,7 +1005,6 @@ template(java_lang_invoke_MemberName,MN_SEARCH_INTERFACES) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_SHIFT) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_MASK) \ - template(MethodHandles,GC_LAMBDA_SUPPORT) \ /*end*/ #define IGNORE_REQ(req_expr) /* req_expr */ @@ -1313,7 +1298,6 @@ {CC"init", CC"("MEM""OBJ")V", FN_PTR(MHN_init_Mem)}, {CC"expand", CC"("MEM")V", FN_PTR(MHN_expand_Mem)}, {CC"resolve", CC"("MEM""CLS")"MEM, FN_PTR(MHN_resolve_Mem)}, - {CC"getConstant", CC"(I)I", FN_PTR(MHN_getConstant)}, // static native int getNamedCon(int which, Object[] name) {CC"getNamedCon", CC"(I["OBJ")I", FN_PTR(MHN_getNamedCon)}, // static native int getMembers(Class defc, String matchName, String matchSig, diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/methodHandles.hpp --- a/hotspot/src/share/vm/prims/methodHandles.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,11 +125,6 @@ return signature_polymorphic_name_id(klass, name) != vmIntrinsics::_none; } - enum { - // format of query to getConstant: - GC_COUNT_GWT = 4, - GC_LAMBDA_SUPPORT = 5 - }; static int get_named_constant(int which, Handle name_box, TRAPS); public: diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/unsafe.cpp --- a/hotspot/src/share/vm/prims/unsafe.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -324,6 +324,24 @@ #endif // not SUPPORTS_NATIVE_CX8 +UNSAFE_ENTRY(jboolean, Unsafe_isBigEndian0(JNIEnv *env, jobject unsafe)) + UnsafeWrapper("Unsafe_IsBigEndian0"); + { +#ifdef VM_LITTLE_ENDIAN + return false; +#else + return true; +#endif + } +UNSAFE_END + +UNSAFE_ENTRY(jint, Unsafe_unalignedAccess0(JNIEnv *env, jobject unsafe)) + UnsafeWrapper("Unsafe_UnalignedAccess0"); + { + return UseUnalignedAccesses; + } +UNSAFE_END + #define DEFINE_GETSETOOP(jboolean, Boolean) \ \ UNSAFE_ENTRY(jboolean, Unsafe_Get##Boolean##140(JNIEnv *env, jobject unsafe, jobject obj, jint offset)) \ @@ -1261,6 +1279,9 @@ {CC"loadFence", CC"()V", FN_PTR(Unsafe_LoadFence)}, {CC"storeFence", CC"()V", FN_PTR(Unsafe_StoreFence)}, {CC"fullFence", CC"()V", FN_PTR(Unsafe_FullFence)}, + + {CC"isBigEndian0", CC"()Z", FN_PTR(Unsafe_isBigEndian0)}, + {CC"unalignedAccess0", CC"()Z", FN_PTR(Unsafe_unalignedAccess0)} }; #undef CC diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -89,6 +89,10 @@ return os::vm_page_size(); WB_END +WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o)) + return os::large_page_size(); +WB_END + class WBIsKlassAliveClosure : public KlassClosure { Symbol* _name; bool _found; @@ -819,46 +823,9 @@ mo.notify_all(); WB_END -void WhiteBox::sweeper_thread_entry(JavaThread* thread, TRAPS) { - guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); - { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - NMethodSweeper::_should_sweep = true; - } - NMethodSweeper::possibly_sweep(); -} - -JavaThread* WhiteBox::create_sweeper_thread(TRAPS) { - // create sweeper thread w/ custom entry -- one iteration instead of loop - CodeCacheSweeperThread* sweeper_thread = new CodeCacheSweeperThread(); - sweeper_thread->set_entry_point(&WhiteBox::sweeper_thread_entry); - - // create j.l.Thread object and associate it w/ sweeper thread - { - // inherit deamon property from current thread - bool is_daemon = java_lang_Thread::is_daemon(JavaThread::current()->threadObj()); - - HandleMark hm(THREAD); - Handle thread_group(THREAD, Universe::system_thread_group()); - const char* name = "WB Sweeper thread"; - sweeper_thread->allocate_threadObj(thread_group, name, is_daemon, THREAD); - } - - { - MutexLocker mu(Threads_lock, THREAD); - Threads::add(sweeper_thread); - } - return sweeper_thread; -} - -WB_ENTRY(jobject, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) - JavaThread* sweeper_thread = WhiteBox::create_sweeper_thread(Thread::current()); - if (sweeper_thread == NULL) { - return NULL; - } - jobject result = JNIHandles::make_local(env, sweeper_thread->threadObj()); - Thread::start(sweeper_thread); - return result; +WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) + // Force a code cache sweep and block until it finished + NMethodSweeper::force_sweep(); WB_END WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) @@ -1296,19 +1263,20 @@ #define CC (char*) static JNINativeMethod methods[] = { - {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, - {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, - {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, + {CC"getObjectAddress0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, + {CC"getObjectSize0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, + {CC"isObjectInOldGen0", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize }, + {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, - {CC"parseCommandLine", + {CC"parseCommandLine0", CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine }, - {CC"addToBootstrapClassLoaderSearch", CC"(Ljava/lang/String;)V", + {CC"addToBootstrapClassLoaderSearch0", CC"(Ljava/lang/String;)V", (void*)&WB_AddToBootstrapClassLoaderSearch}, - {CC"addToSystemClassLoaderSearch", CC"(Ljava/lang/String;)V", + {CC"addToSystemClassLoaderSearch0", CC"(Ljava/lang/String;)V", (void*)&WB_AddToSystemClassLoaderSearch}, {CC"getCompressedOopsMaxHeapSize", CC"()J", (void*)&WB_GetCompressedOopsMaxHeapSize}, @@ -1318,7 +1286,7 @@ {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, - {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, + {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, @@ -1339,29 +1307,29 @@ #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I", + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_DeoptimizeMethod }, - {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;Z)Z", + {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, - {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;IZ)Z", + {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", (void*)&WB_IsMethodCompilable}, - {CC"isMethodQueuedForCompilation", + {CC"isMethodQueuedForCompilation0", CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation}, - {CC"makeMethodNotCompilable", + {CC"makeMethodNotCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable}, - {CC"testSetDontInlineMethod", + {CC"testSetDontInlineMethod0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod}, - {CC"getMethodCompilationLevel", + {CC"getMethodCompilationLevel0", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel}, - {CC"getMethodEntryBci", + {CC"getMethodEntryBci0", CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci}, {CC"getCompileQueueSize", CC"(I)I", (void*)&WB_GetCompileQueueSize}, - {CC"testSetForceInlineMethod", + {CC"testSetForceInlineMethod0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod}, - {CC"enqueueMethodForCompilation", + {CC"enqueueMethodForCompilation0", CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, - {CC"clearMethodState", + {CC"clearMethodState0", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, @@ -1400,9 +1368,9 @@ {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC }, {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, - {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", + {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, - {CC"forceNMethodSweep0", CC"()Ljava/lang/Thread;", (void*)&WB_ForceNMethodSweep }, + {CC"forceNMethodSweep", CC"()V", (void*)&WB_ForceNMethodSweep }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, @@ -1412,7 +1380,7 @@ {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, - {CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/prims/whitebox.hpp --- a/hotspot/src/share/vm/prims/whitebox.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -70,8 +70,6 @@ Symbol* signature_symbol); static const char* lookup_jstring(const char* field_name, oop object); static bool lookup_bool(const char* field_name, oop object); - static void sweeper_thread_entry(JavaThread* thread, TRAPS); - static JavaThread* create_sweeper_thread(TRAPS); static int get_blob_type(const CodeBlob* code); static CodeHeap* get_code_heap(int blob_type); static CodeBlob* allocate_code_blob(int size, int blob_type); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -92,6 +92,8 @@ bool Arguments::_UseOnStackReplacement = UseOnStackReplacement; bool Arguments::_BackgroundCompilation = BackgroundCompilation; bool Arguments::_ClipInlining = ClipInlining; +intx Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog; +intx Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold; char* Arguments::SharedArchivePath = NULL; @@ -1012,6 +1014,14 @@ AlwaysCompileLoopMethods = Arguments::_AlwaysCompileLoopMethods; UseOnStackReplacement = Arguments::_UseOnStackReplacement; BackgroundCompilation = Arguments::_BackgroundCompilation; + if (TieredCompilation) { + if (FLAG_IS_DEFAULT(Tier3InvokeNotifyFreqLog)) { + Tier3InvokeNotifyFreqLog = Arguments::_Tier3InvokeNotifyFreqLog; + } + if (FLAG_IS_DEFAULT(Tier4InvocationThreshold)) { + Tier4InvocationThreshold = Arguments::_Tier4InvocationThreshold; + } + } // Change from defaults based on mode switch (mode) { @@ -2525,6 +2535,10 @@ Arguments::_UseOnStackReplacement = UseOnStackReplacement; Arguments::_ClipInlining = ClipInlining; Arguments::_BackgroundCompilation = BackgroundCompilation; + if (TieredCompilation) { + Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog; + Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold; + } // Setup flags for mixed which is the default set_mode_flags(_mixed); @@ -3086,7 +3100,7 @@ FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize); } -#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. +#if !defined(_ALLBSD_SOURCE) && !defined(AIX) // UseLargePages is not yet supported on BSD and AIX. FLAG_SET_DEFAULT(UseLargePages, true); #endif @@ -3145,7 +3159,8 @@ uintx max_tenuring_thresh = 0; if(!parse_uintx(tail, &max_tenuring_thresh, 0)) { jio_fprintf(defaultStream::error_stream(), - "Invalid MaxTenuringThreshold: %s\n", option->optionString); + "Improperly specified VM option 'MaxTenuringThreshold=%s'\n", tail); + return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh); @@ -3808,7 +3823,7 @@ hotspotrc, hotspotrc); } -#ifdef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. +#if defined(_ALLBSD_SOURCE) || defined(AIX) // UseLargePages is not yet supported on BSD and AIX. UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); #endif diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -323,6 +323,8 @@ static bool _BackgroundCompilation; static bool _ClipInlining; static bool _CIDynamicCompilePriority; + static intx _Tier3InvokeNotifyFreqLog; + static intx _Tier4InvocationThreshold; // Tiered static void set_tiered_flags(); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -1861,6 +1861,7 @@ "speculate_null_check", "rtm_state_change", "unstable_if", + "unstable_fused_if", "tenured" }; const char* Deoptimization::_trap_action_name[] = { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/deoptimization.hpp --- a/hotspot/src/share/vm/runtime/deoptimization.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -63,6 +63,7 @@ Reason_speculate_null_check, // saw unexpected null from type speculation Reason_rtm_state_change, // rtm state change detected Reason_unstable_if, // a branch predicted always false was taken + Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. // Reason_tenured is counted separately, add normal counted Reasons above. // Related to MethodData::_trap_hist_limit where Reason_tenured isn't included @@ -326,6 +327,8 @@ return Reason_null_check; else if (reason == Reason_unstable_if) return Reason_intrinsic; + else if (reason == Reason_unstable_fused_if) + return Reason_range_check; else return Reason_none; } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -3909,7 +3909,10 @@ "Enable event-based tracing") \ \ product(bool, UseLockedTracing, false, \ - "Use locked-tracing when doing event-based tracing") + "Use locked-tracing when doing event-based tracing") \ + \ + diagnostic(bool, UseUnalignedAccesses, false, \ + "Use unaligned memory accesses in sun.misc.Unsafe") /* * Macros for factoring of globals diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/rtmLocking.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/runtime/rtmLocking.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "utilities/globalDefinitions.hpp" + +#if INCLUDE_RTM_OPT + +#include "memory/allocation.inline.hpp" +#include "runtime/task.hpp" +#include "runtime/rtmLocking.hpp" + + +// One-shot PeriodicTask subclass for enabling RTM locking +uintx RTMLockingCounters::_calculation_flag = 0; + +class RTMLockingCalculationTask : public PeriodicTask { + public: + RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } + + virtual void task() { + RTMLockingCounters::_calculation_flag = 1; + // Reclaim our storage and disenroll ourself + delete this; + } +}; + +void RTMLockingCounters::init() { + if (UseRTMLocking && RTMLockingCalculationDelay > 0) { + RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); + task->enroll(); + } else { + _calculation_flag = 1; + } +} + +//------------------------------print_on------------------------------- +void RTMLockingCounters::print_on(outputStream* st) { + tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); + tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); + } +} + +#endif diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -144,6 +144,7 @@ int NMethodSweeper::_seen = 0; // Nof. nmethod we have currently processed in current pass of CodeCache volatile bool NMethodSweeper::_should_sweep = true; // Indicates if we should invoke the sweeper +volatile bool NMethodSweeper::_force_sweep = false;// Indicates if we should force a sweep volatile int NMethodSweeper::_bytes_changed = 0; // Counts the total nmethod size if the nmethod changed from: // 1) alive -> not_entrant // 2) not_entrant -> zombie @@ -276,6 +277,23 @@ } /** + * Wakes up the sweeper thread and forces a sweep. Blocks until it finished. + */ +void NMethodSweeper::force_sweep() { + ThreadBlockInVM tbivm(JavaThread::current()); + MutexLockerEx waiter(CodeCache_lock, Mutex::_no_safepoint_check_flag); + // Request forced sweep + _force_sweep = true; + while (_force_sweep) { + // Notify sweeper that we want to force a sweep and wait for completion. + // In case a sweep currently takes place we timeout and try again because + // we want to enforce a full sweep. + CodeCache_lock->notify(); + CodeCache_lock->wait(Mutex::_no_safepoint_check_flag, 1000); + } +} + +/** * Handle a safepoint request */ void NMethodSweeper::handle_safepoint_request() { @@ -335,6 +353,9 @@ } } + // Remember if this was a forced sweep + bool forced = _force_sweep; + // Force stack scanning if there is only 10% free space in the code cache. // We force stack scanning only non-profiled code heap gets full, since critical // allocation go to the non-profiled heap and we must be make sure that there is @@ -344,7 +365,7 @@ do_stack_scanning(); } - if (_should_sweep) { + if (_should_sweep || forced) { init_sweeper_log(); sweep_code_cache(); } @@ -356,12 +377,20 @@ _should_sweep = false; // If there was enough state change, 'possibly_enable_sweeper()' // sets '_should_sweep' to true - possibly_enable_sweeper(); + possibly_enable_sweeper(); // Reset _bytes_changed only if there was enough state change. _bytes_changed // can further increase by calls to 'report_state_change'. if (_should_sweep) { _bytes_changed = 0; } + + if (forced) { + // Notify requester that forced sweep finished + assert(_force_sweep, "Should be a forced sweep"); + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _force_sweep = false; + CodeCache_lock->notify(); + } } void NMethodSweeper::sweep_code_cache() { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -54,7 +54,6 @@ // nmethod's space is freed. class NMethodSweeper : public AllStatic { - friend class WhiteBox; private: enum MethodStateChange { None, @@ -71,6 +70,7 @@ static volatile int _sweep_started; // Flag to control conc sweeper static volatile bool _should_sweep; // Indicates if we should invoke the sweeper + static volatile bool _force_sweep; // Indicates if we should force a sweep static volatile int _bytes_changed; // Counts the total nmethod size if the nmethod changed from: // 1) alive -> not_entrant // 2) not_entrant -> zombie @@ -117,6 +117,7 @@ static void mark_active_nmethods(); // Invoked at the end of each safepoint static void sweeper_loop(); static void notify(int code_blob_type); // Possibly start the sweeper thread. + static void force_sweep(); static int hotness_counter_reset_val(); static void report_state_change(nmethod* nm); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/thread.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -272,6 +272,11 @@ #endif // ASSERT } +// Non-inlined version to be used where thread.inline.hpp shouldn't be included. +Thread* Thread::current_noinline() { + return Thread::current(); +} + void Thread::initialize_thread_local_storage() { // Note: Make sure this method only calls // non-blocking operations. Otherwise, it might not work @@ -754,13 +759,9 @@ return true; } else { guarantee(res == strong_roots_parity, "Or else what?"); - assert(SharedHeap::heap()->workers()->active_workers() > 0, - "Should only fail when parallel."); return false; } } - assert(SharedHeap::heap()->workers()->active_workers() > 0, - "Should only fail when parallel."); return false; } @@ -4056,7 +4057,7 @@ "Not in range."); } -#ifndef PRODUCT +#ifdef ASSERT void Threads::assert_all_threads_claimed() { ALL_JAVA_THREADS(p) { const int thread_parity = p->oops_do_parity(); @@ -4064,22 +4065,9 @@ err_msg("Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity)); } } -#endif // PRODUCT - -void Threads::possibly_parallel_oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { - // Introduce a mechanism allowing parallel threads to claim threads as - // root groups. Overhead should be small enough to use all the time, - // even in sequential code. - SharedHeap* sh = SharedHeap::heap(); - // Cannot yet substitute active_workers for n_par_threads - // because of G1CollectedHeap::verify() use of - // SharedHeap::process_roots(). n_par_threads == 0 will - // turn off parallelism in process_roots while active_workers - // is being used for parallelism elsewhere. - bool is_par = sh->n_par_threads() > 0; - assert(!is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); +#endif // ASSERT + +void Threads::possibly_parallel_oops_do(bool is_par, OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { int cp = Threads::thread_claim_parity(); ALL_JAVA_THREADS(p) { if (p->claim_oops_do(is_par, cp)) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/thread.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -324,6 +324,8 @@ // Returns the current thread static inline Thread* current(); + // ... without having to include thread.inline.hpp. + static Thread* current_noinline(); // Common thread operations static void set_priority(Thread* thread, ThreadPriority priority); @@ -1886,15 +1888,28 @@ // Does not include JNI_VERSION_1_1 static jboolean is_supported_jni_version(jint version); + // The "thread claim parity" provides a way for threads to be claimed + // by parallel worker tasks. + // + // Each thread contains a a "parity" field. A task will claim the + // thread only if its parity field is the same as the global parity, + // which is updated by calling change_thread_claim_parity(). + // + // For this to work change_thread_claim_parity() needs to be called + // exactly once in sequential code before starting parallel tasks + // that should claim threads. + // + // New threads get their parity set to 0 and change_thread_claim_parity() + // never set the global parity to 0. static int thread_claim_parity() { return _thread_claim_parity; } static void change_thread_claim_parity(); + static void assert_all_threads_claimed() NOT_DEBUG_RETURN; - static void assert_all_threads_claimed() PRODUCT_RETURN; // Apply "f->do_oop" to all root oops in all threads. // This version may only be called by sequential code. static void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); // This version may be called by sequential or parallel code. - static void possibly_parallel_oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); + static void possibly_parallel_oops_do(bool is_par, OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); // This creates a list of GCTasks, one per thread. static void create_thread_roots_tasks(GCTaskQueue* q); // This creates a list of GCTasks, one per thread, for marking objects. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -37,13 +37,22 @@ _alignment(0), _special(false), _executable(false) { } -ReservedSpace::ReservedSpace(size_t size) { +ReservedSpace::ReservedSpace(size_t size, size_t preferred_page_size) { + bool has_preferred_page_size = preferred_page_size != 0; // Want to use large pages where possible and pad with small pages. - size_t page_size = os::page_size_for_region_unaligned(size, 1); + size_t page_size = has_preferred_page_size ? preferred_page_size : os::page_size_for_region_unaligned(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); - // Don't force the alignment to be large page aligned, - // since that will waste memory. - size_t alignment = os::vm_allocation_granularity(); + size_t alignment; + if (large_pages && has_preferred_page_size) { + alignment = MAX2(page_size, (size_t)os::vm_allocation_granularity()); + // ReservedSpace initialization requires size to be aligned to the given + // alignment. Align the size up. + size = align_size_up(size, alignment); + } else { + // Don't force the alignment to be large page aligned, + // since that will waste memory. + alignment = os::vm_allocation_granularity(); + } initialize(size, alignment, large_pages, NULL, false); } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/virtualspace.hpp --- a/hotspot/src/share/vm/runtime/virtualspace.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -51,7 +51,11 @@ public: // Constructor ReservedSpace(); - ReservedSpace(size_t size); + // Initialize the reserved space with the given size. If preferred_page_size + // is set, use this as minimum page size/alignment. This may waste some space + // if the given size is not aligned to that value, as the reservation will be + // aligned up to the final alignment in this case. + ReservedSpace(size_t size, size_t preferred_page_size = 0); ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address = NULL); ReservedSpace(size_t size, size_t alignment, bool large, bool executable); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -558,7 +558,6 @@ static_field(GenCollectedHeap, _gch, GenCollectedHeap*) \ nonstatic_field(GenCollectedHeap, _young_gen, Generation*) \ nonstatic_field(GenCollectedHeap, _old_gen, Generation*) \ - nonstatic_field(GenCollectedHeap, _n_gens, int) \ \ nonstatic_field(GenCollectorPolicy, _young_gen_spec, GenerationSpec*) \ nonstatic_field(GenCollectorPolicy, _old_gen_spec, GenerationSpec*) \ @@ -1501,8 +1500,7 @@ /******************************************/ \ \ declare_toplevel_type(CollectedHeap) \ - declare_type(SharedHeap, CollectedHeap) \ - declare_type(GenCollectedHeap, SharedHeap) \ + declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ declare_type(DefNewGeneration, Generation) \ declare_type(CardGeneration, Generation) \ @@ -1985,13 +1983,18 @@ declare_c2_type(PowDNode, Node) \ declare_c2_type(ReverseBytesINode, Node) \ declare_c2_type(ReverseBytesLNode, Node) \ + declare_c2_type(ReductionNode, Node) \ declare_c2_type(VectorNode, Node) \ declare_c2_type(AddVBNode, VectorNode) \ declare_c2_type(AddVSNode, VectorNode) \ declare_c2_type(AddVINode, VectorNode) \ + declare_c2_type(AddReductionVINode, ReductionNode) \ declare_c2_type(AddVLNode, VectorNode) \ + declare_c2_type(AddReductionVLNode, ReductionNode) \ declare_c2_type(AddVFNode, VectorNode) \ + declare_c2_type(AddReductionVFNode, ReductionNode) \ declare_c2_type(AddVDNode, VectorNode) \ + declare_c2_type(AddReductionVDNode, ReductionNode) \ declare_c2_type(SubVBNode, VectorNode) \ declare_c2_type(SubVSNode, VectorNode) \ declare_c2_type(SubVINode, VectorNode) \ @@ -2000,8 +2003,11 @@ declare_c2_type(SubVDNode, VectorNode) \ declare_c2_type(MulVSNode, VectorNode) \ declare_c2_type(MulVINode, VectorNode) \ + declare_c2_type(MulReductionVINode, ReductionNode) \ declare_c2_type(MulVFNode, VectorNode) \ + declare_c2_type(MulReductionVFNode, ReductionNode) \ declare_c2_type(MulVDNode, VectorNode) \ + declare_c2_type(MulReductionVDNode, ReductionNode) \ declare_c2_type(DivVFNode, VectorNode) \ declare_c2_type(DivVDNode, VectorNode) \ declare_c2_type(LShiftVBNode, VectorNode) \ @@ -2257,8 +2263,6 @@ declare_constant(CollectedHeap::ParallelScavengeHeap) \ declare_constant(CollectedHeap::G1CollectedHeap) \ \ - declare_constant(GenCollectedHeap::max_gens) \ - \ /* constants from Generation::Name enum */ \ \ declare_constant(Generation::DefNew) \ @@ -2516,6 +2520,7 @@ declare_constant(Deoptimization::Reason_speculate_null_check) \ declare_constant(Deoptimization::Reason_rtm_state_change) \ declare_constant(Deoptimization::Reason_unstable_if) \ + declare_constant(Deoptimization::Reason_unstable_fused_if) \ declare_constant(Deoptimization::Reason_tenured) \ declare_constant(Deoptimization::Reason_LIMIT) \ declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/services/memoryManager.hpp --- a/hotspot/src/share/vm/services/memoryManager.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/services/memoryManager.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -53,20 +53,6 @@ volatile instanceOop _memory_mgr_obj; public: - enum Name { - Abstract, - CodeCache, - Metaspace, - Copy, - MarkSweepCompact, - ParNew, - ConcurrentMarkSweep, - PSScavenge, - PSMarkSweep, - G1YoungGen, - G1OldGen - }; - MemoryManager(); int num_memory_pools() const { return _num_pools; } @@ -80,7 +66,6 @@ bool is_manager(instanceHandle mh) { return mh() == _memory_mgr_obj; } virtual instanceOop get_memory_manager_instance(TRAPS); - virtual MemoryManager::Name kind() { return MemoryManager::Abstract; } virtual bool is_gc_memory_manager() { return false; } virtual const char* name() = 0; @@ -98,7 +83,6 @@ static GCMemoryManager* get_psMarkSweep_memory_manager(); static GCMemoryManager* get_g1YoungGen_memory_manager(); static GCMemoryManager* get_g1OldGen_memory_manager(); - }; class CodeCacheMemoryManager : public MemoryManager { @@ -106,16 +90,14 @@ public: CodeCacheMemoryManager() : MemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::CodeCache; } - const char* name() { return "CodeCacheManager"; } + const char* name() { return "CodeCacheManager"; } }; class MetaspaceMemoryManager : public MemoryManager { public: MetaspaceMemoryManager() : MemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::Metaspace; } - const char *name() { return "Metaspace Manager"; } + const char* name() { return "Metaspace Manager"; } }; class GCStatInfo : public ResourceObj { @@ -202,7 +184,6 @@ void set_notification_enabled(bool enabled) { _notification_enabled = enabled; } bool is_notification_enabled() { return _notification_enabled; } - virtual MemoryManager::Name kind() = 0; }; // These subclasses of GCMemoryManager are defined to include @@ -213,8 +194,7 @@ public: CopyMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::Copy; } - const char* name() { return "Copy"; } + const char* name() { return "Copy"; } }; class MSCMemoryManager : public GCMemoryManager { @@ -222,9 +202,7 @@ public: MSCMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::MarkSweepCompact; } - const char* name() { return "MarkSweepCompact"; } - + const char* name() { return "MarkSweepCompact"; } }; class ParNewMemoryManager : public GCMemoryManager { @@ -232,9 +210,7 @@ public: ParNewMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::ParNew; } - const char* name() { return "ParNew"; } - + const char* name() { return "ParNew"; } }; class CMSMemoryManager : public GCMemoryManager { @@ -242,9 +218,7 @@ public: CMSMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::ConcurrentMarkSweep; } - const char* name() { return "ConcurrentMarkSweep";} - + const char* name() { return "ConcurrentMarkSweep";} }; class PSScavengeMemoryManager : public GCMemoryManager { @@ -252,9 +226,7 @@ public: PSScavengeMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::PSScavenge; } - const char* name() { return "PS Scavenge"; } - + const char* name() { return "PS Scavenge"; } }; class PSMarkSweepMemoryManager : public GCMemoryManager { @@ -262,8 +234,7 @@ public: PSMarkSweepMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::PSMarkSweep; } - const char* name() { return "PS MarkSweep"; } + const char* name() { return "PS MarkSweep"; } }; class G1YoungGenMemoryManager : public GCMemoryManager { @@ -271,8 +242,7 @@ public: G1YoungGenMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::G1YoungGen; } - const char* name() { return "G1 Young Generation"; } + const char* name() { return "G1 Young Generation"; } }; class G1OldGenMemoryManager : public GCMemoryManager { @@ -280,8 +250,7 @@ public: G1OldGenMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::G1OldGen; } - const char* name() { return "G1 Old Generation"; } + const char* name() { return "G1 Old Generation"; } }; #endif // SHARE_VM_SERVICES_MEMORYMANAGER_HPP diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/services/memoryService.cpp --- a/hotspot/src/share/vm/services/memoryService.cpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/services/memoryService.cpp Fri Apr 17 14:37:20 2015 -0700 @@ -126,9 +126,8 @@ CollectorPolicy* policy = heap->collector_policy(); assert(policy->is_generation_policy(), "Only support two generations"); - guarantee(heap->n_gens() == 2, "Only support two-generation heap"); - GenCollectorPolicy* gen_policy = policy->as_generation_policy(); + guarantee(gen_policy->number_of_generations() == 2, "Only support two-generation heap"); if (gen_policy != NULL) { Generation::Name kind = gen_policy->young_gen_spec()->name(); switch (kind) { diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -407,14 +407,6 @@ // Machine dependent stuff -#if defined(X86) && defined(COMPILER2) && !defined(JAVASE_EMBEDDED) -// Include Restricted Transactional Memory lock eliding optimization -#define INCLUDE_RTM_OPT 1 -#define RTM_OPT_ONLY(code) code -#else -#define INCLUDE_RTM_OPT 0 -#define RTM_OPT_ONLY(code) -#endif // States of Restricted Transactional Memory usage. enum RTMState { NoRTM = 0x2, // Don't use RTM @@ -446,6 +438,15 @@ # include "globalDefinitions_aarch64.hpp" #endif +#ifndef INCLUDE_RTM_OPT +#define INCLUDE_RTM_OPT 0 +#endif +#if INCLUDE_RTM_OPT +#define RTM_OPT_ONLY(code) code +#else +#define RTM_OPT_ONLY(code) +#endif + // To assure the IRIW property on processors that are not multiple copy // atomic, sync instructions must be issued between volatile reads to // assure their ordering, instead of after volatile stores. @@ -1345,6 +1346,13 @@ return (intptr_t) p; } +// swap a & b +template static void swap(T& a, T& b) { + T tmp = a; + a = b; + b = tmp; +} + // Printf-style formatters for fixed- and variable-width types as pointers and // integers. These are derived from the definitions in inttypes.h. If the platform // doesn't provide appropriate definitions, they should be provided in diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/utilities/stack.hpp --- a/hotspot/src/share/vm/utilities/stack.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/utilities/stack.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -96,11 +96,16 @@ public: friend class StackIterator; + // Number of elements that fit in 4K bytes minus the size of two pointers + // (link field and malloc header). + static const size_t _default_segment_size = (4096 - 2 * sizeof(E*)) / sizeof(E); + static size_t default_segment_size() { return _default_segment_size; } + // segment_size: number of items per segment // max_cache_size: maxmium number of *segments* to cache // max_size: maximum number of items allowed, rounded to a multiple of // the segment size (0 == unlimited) - inline Stack(size_t segment_size = default_segment_size(), + inline Stack(size_t segment_size = _default_segment_size, size_t max_cache_size = 4, size_t max_size = 0); inline ~Stack() { clear(true); } @@ -122,8 +127,6 @@ // clear_cache is true, also release any cached segments. void clear(bool clear_cache = false); - static inline size_t default_segment_size(); - protected: // Each segment includes space for _seg_size elements followed by a link // (pointer) to the previous segment; the space is allocated as a single block diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/utilities/stack.inline.hpp --- a/hotspot/src/share/vm/utilities/stack.inline.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/utilities/stack.inline.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -86,14 +86,6 @@ } template -size_t Stack::default_segment_size() -{ - // Number of elements that fit in 4K bytes minus the size of two pointers - // (link field and malloc header). - return (4096 - 2 * sizeof(E*)) / sizeof(E); -} - -template size_t Stack::adjust_segment_size(size_t seg_size) { const size_t elem_sz = sizeof(E); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/src/share/vm/utilities/workgroup.hpp --- a/hotspot/src/share/vm/utilities/workgroup.hpp Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/src/share/vm/utilities/workgroup.hpp Fri Apr 17 14:37:20 2015 -0700 @@ -340,18 +340,6 @@ } }; -// Work gangs in garbage collectors: 2009-06-10 -// -// SharedHeap - work gang for stop-the-world parallel collection. -// Used by -// ParNewGeneration -// CMSParRemarkTask -// CMSRefProcTaskExecutor -// G1CollectedHeap -// G1ParFinalCountTask -// ConcurrentMark -// CMSCollector - // A class that acts as a synchronisation barrier. Workers enter // the barrier and must wait until all other workers have entered // before any of them may leave. diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/TEST.groups Fri Apr 17 14:37:20 2015 -0700 @@ -394,6 +394,7 @@ hotspot_gc = \ sanity/ExecuteInternalVMTests.java \ gc/ \ + -gc/g1/TestGreyReclaimedHumongousObjects.java \ -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java hotspot_gc_closed = \ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/arraycopy/TestArrayCopyBadReexec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyBadReexec.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8073866 + * @summary Fix for 8064703 may also cause stores between the allocation and arraycopy to be rexecuted after a deoptimization + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyBadReexec + * + */ + +public class TestArrayCopyBadReexec { + + static int val; + + static int[] m1(int[] src, int l) { + if (src == null) { + return null; + } + int[] dest = new int[10]; + val++; + try { + System.arraycopy(src, 0, dest, 0, l); + } catch (IndexOutOfBoundsException npe) { + } + return dest; + } + + static public void main(String[] args) { + int[] src = new int[10]; + int[] res = null; + boolean success = true; + + for (int i = 0; i < 20000; i++) { + m1(src, 10); + } + + int val_before = val; + + m1(src, -1); + + if (val - val_before != 1) { + System.out.println("Bad increment: " + (val - val_before)); + throw new RuntimeException("Test failed"); + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java --- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java Fri Apr 17 14:37:20 2015 -0700 @@ -76,7 +76,7 @@ static TestArrayCopyNoInit[] m5(Object[] src) { Object tmp = src[0]; TestArrayCopyNoInit[] dest = new TestArrayCopyNoInit[10]; - System.arraycopy(src, 0, dest, 0, 0); + System.arraycopy(src, 0, dest, 0, 10); return dest; } @@ -110,7 +110,7 @@ static H[] m6(Object[] src) { Object tmp = src[0]; H[] dest = new H[10]; - System.arraycopy(src, 0, dest, 0, 0); + System.arraycopy(src, 0, dest, 0, 10); return dest; } diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/arraycopy/TestArrayCopyOfStopped.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyOfStopped.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8074676 + * @summary after guards in Arrays.copyOf() intrinsic, control may become top + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyOfStopped + * + */ + +import java.util.Arrays; + +public class TestArrayCopyOfStopped { + static class A { + } + + static class B { + } + + static final B[] array_of_bs = new B[10]; + static final A[] array_of_as = new A[10]; + + static Object[] m1_helper(Object[] array, boolean flag) { + if (flag) { + return Arrays.copyOf(array, 10, A[].class); + } + return null; + } + + static Object[] m1(boolean flag) { + return m1_helper(array_of_bs, flag); + } + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + m1_helper(array_of_as, (i%2) == 0); + } + + for (int i = 0; i < 20000; i++) { + m1(false); + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/arraycopy/TestArrayCopyStoppedAfterGuards.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyStoppedAfterGuards.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8075921 + * @summary control becomes top after arraycopy guards and confuses tighly coupled allocation logic + * @run main/othervm -Xcomp -XX:CompileOnly=TestArrayCopyStoppedAfterGuards.test,System.arraycopy TestArrayCopyStoppedAfterGuards + * + */ + +public class TestArrayCopyStoppedAfterGuards { + + static void test() { + Object src = new Object(); + int[] dst = new int[10]; + System.arraycopy(src, 0, dst, 0, 10); + } + + static public void main(String[] args) { + // warmup + Object o = new Object(); + int[] src = new int[10]; + int[] dst = new int[10]; + System.arraycopy(src, 0, dst, 0, 10); + + try { + test(); + } catch(ArrayStoreException ase) {} + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java --- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Fri Apr 17 14:37:20 2015 -0700 @@ -37,7 +37,6 @@ /* * @test PoolsIndependenceTest - * @ignore 8068385 * @library /testlibrary /../../test/lib * @build PoolsIndependenceTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/inlining/DefaultMethodsDependencies.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/inlining/DefaultMethodsDependencies.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8069263 + * @summary Deoptimization between array allocation and arraycopy may result in non initialized array + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=DefaultMethodsDependencies::test -XX:CompileOnly=DefaultMethodsDependencies$I2::m1 DefaultMethodsDependencies + * + */ + +public class DefaultMethodsDependencies { + + interface I1 { + void m1(); + // triggers processing of default methods in C1 + default void m2() { + } + } + + interface I2 extends I1 { + // added to C2 as default method + default void m1() { + } + } + + static abstract class C1 implements I1 { + } + + static class C2 extends C1 implements I2 { + } + + static void test(C1 obj) { + obj.m1(); + } + + static public void main(String[] args) { + C2 obj = new C2(); + for (int i = 0; i < 20000; i++) { + test(obj); + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java --- a/hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java Fri Apr 17 14:37:20 2015 -0700 @@ -34,6 +34,7 @@ * -XX:CompileCommand=inline,java.math.BigInteger::multiply TestMultiplyToLen */ +import java.util.Arrays; import java.util.Random; import java.math.*; @@ -97,12 +98,36 @@ newsum = newsum.add(newres); if (!bytecompare(oldres,newres)) { + System.out.println(b1); + System.out.println(b2); + System.out.print("mismatch for:b1:" + stringify(b1) + " :b2:" + stringify(b2) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres)); + throw new Exception("Failed"); + } + } + + // Test carry propagation. Multiple carries during bignum + // multiplication are rare (especially when using 64-bit + // arithmetic) so we have to provoke them deliberately. + for (int j = 4; j <= 396; j += 4) { + byte[] bytes = new byte[j]; + Arrays.fill(bytes, (byte)255); + b1 = new BigInteger(bytes); + b2 = new BigInteger(bytes); + + oldres = base_multiply(b1,b2); + newres = new_multiply(b1,b2); + + oldsum = oldsum.add(oldres); + newsum = newsum.add(newres); + + if (!bytecompare(oldres,newres)) { System.out.print("mismatch for:b1:" + stringify(b1) + " :b2:" + stringify(b2) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres)); System.out.println(b1); System.out.println(b2); throw new Exception("Failed"); } } + if (!bytecompare(oldsum,newsum)) { System.out.println("Failure: oldsum:" + stringify(oldsum) + " newsum:" + stringify(newsum)); throw new Exception("Failed"); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,371 @@ +// +// Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2015, Red Hat Inc. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// + +import com.oracle.java.testlibrary.Utils; +import static java.lang.Math.abs; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import java.util.Random; +import java.util.Arrays; + +/** + * @test + * @bug 8026049 + * @library /testlibrary + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses HeapByteBufferTest + * @run main/othervm HeapByteBufferTest + * @summary Verify that byte buffers are correctly accessed. + */ + +// A wrapper for a ByteBuffer which maintains a backing array and a +// position. Whenever this wrapper is written the backing array and +// the wrapped byte buffer are updated together, and whenever it is +// read we check that the ByteBuffer and the backing array are identical. + +class MyByteBuffer { + final ByteBuffer buf; + final byte[] bytes; + int pos; + ByteOrder byteOrder = BIG_ENDIAN; + + MyByteBuffer(ByteBuffer buf, byte[] bytes) { + this.buf = buf; + this.bytes = Arrays.copyOf(bytes, bytes.length); + pos = 0; + } + + public final MyByteBuffer order(ByteOrder bo) { + byteOrder = bo; + buf.order(bo); + return this; + } + + static MyByteBuffer wrap(byte[] bytes) { + return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes); + } + + int capacity() { return bytes.length; } + int position() { + if (buf.position() != pos) + throw new RuntimeException(); + return buf.position(); + } + + byte[] array() { return buf.array(); } + byte[] backingArray() { return bytes; } + + private static byte long7(long x) { return (byte)(x >> 56); } + private static byte long6(long x) { return (byte)(x >> 48); } + private static byte long5(long x) { return (byte)(x >> 40); } + private static byte long4(long x) { return (byte)(x >> 32); } + private static byte long3(long x) { return (byte)(x >> 24); } + private static byte long2(long x) { return (byte)(x >> 16); } + private static byte long1(long x) { return (byte)(x >> 8); } + private static byte long0(long x) { return (byte)(x ); } + + private static byte int3(int x) { return (byte)(x >> 24); } + private static byte int2(int x) { return (byte)(x >> 16); } + private static byte int1(int x) { return (byte)(x >> 8); } + private static byte int0(int x) { return (byte)(x ); } + + private static byte short1(short x) { return (byte)(x >> 8); } + private static byte short0(short x) { return (byte)(x ); } + + byte _get(long i) { return bytes[(int)i]; } + void _put(long i, byte x) { bytes[(int)i] = x; } + + private void putLongX(long a, long x) { + if (byteOrder == BIG_ENDIAN) { + x = Long.reverseBytes(x); + } + _put(a + 7, long7(x)); + _put(a + 6, long6(x)); + _put(a + 5, long5(x)); + _put(a + 4, long4(x)); + _put(a + 3, long3(x)); + _put(a + 2, long2(x)); + _put(a + 1, long1(x)); + _put(a , long0(x)); + } + + private void putIntX(long a, int x) { + if (byteOrder == BIG_ENDIAN) { + x = Integer.reverseBytes(x); + } + _put(a + 3, int3(x)); + _put(a + 2, int2(x)); + _put(a + 1, int1(x)); + _put(a , int0(x)); + } + + private void putShortX(int bi, short x) { + if (byteOrder == BIG_ENDIAN) { + x = Short.reverseBytes(x); + } + _put(bi , short0(x)); + _put(bi + 1, short1(x)); + } + + static private int makeInt(byte b3, byte b2, byte b1, byte b0) { + return (((b3 ) << 24) | + ((b2 & 0xff) << 16) | + ((b1 & 0xff) << 8) | + ((b0 & 0xff) )); + } + int getIntX(long a) { + int x = makeInt(_get(a + 3), + _get(a + 2), + _get(a + 1), + _get(a)); + if (byteOrder == BIG_ENDIAN) { + x = Integer.reverseBytes(x); + } + return x; + } + + static private long makeLong(byte b7, byte b6, byte b5, byte b4, + byte b3, byte b2, byte b1, byte b0) + { + return ((((long)b7 ) << 56) | + (((long)b6 & 0xff) << 48) | + (((long)b5 & 0xff) << 40) | + (((long)b4 & 0xff) << 32) | + (((long)b3 & 0xff) << 24) | + (((long)b2 & 0xff) << 16) | + (((long)b1 & 0xff) << 8) | + (((long)b0 & 0xff) )); + } + + long getLongX(long a) { + long x = makeLong(_get(a + 7), + _get(a + 6), + _get(a + 5), + _get(a + 4), + _get(a + 3), + _get(a + 2), + _get(a + 1), + _get(a)); + if (byteOrder == BIG_ENDIAN) { + x = Long.reverseBytes(x); + } + return x; + } + + static private short makeShort(byte b1, byte b0) { + return (short)((b1 << 8) | (b0 & 0xff)); + } + + short getShortX(long a) { + short x = makeShort(_get(a + 1), + _get(a )); + if (byteOrder == BIG_ENDIAN) { + x = Short.reverseBytes(x); + } + return x; + } + + double getDoubleX(long a) { + long x = getLongX(a); + return Double.longBitsToDouble(x); + } + + double getFloatX(long a) { + int x = getIntX(a); + return Float.intBitsToFloat(x); + } + + void ck(long x, long y) { + if (x != y) { + throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); + } + } + + void ck(double x, double y) { + if (x == x && y == y && x != y) { + ck(x, y); + } + } + + long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); } + int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); } + short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); } + char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); } + double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); } + float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); } + + void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); } + void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); } + void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); } + void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); } + void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); } + void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); } + + long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; } + int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; } + short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; } + char getChar() { ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; } + double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; } + float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; } + + void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); } + void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); } + void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); } + void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); } + void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); } + void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); } + + void rewind() { pos = 0; buf.rewind(); } +} + +public class HeapByteBufferTest implements Runnable { + + Random random = Utils.getRandomInstance(); + MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]); + + int randomOffset(Random r, MyByteBuffer buf, int size) { + return r.nextInt(buf.capacity() - size); + } + + long iterations; + + HeapByteBufferTest(long iterations) { + this.iterations = iterations; + } + + // The core of the test. Walk over the buffer reading and writing + // random data, XORing it as we go. We can detect writes in the + // wrong place, writes which are too long or too short, and reads + // or writes of the wrong data, + void step(Random r) { + data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN); + + data.rewind(); + while (data.position() < data.capacity()) + data.putLong(data.getLong() ^ random.nextLong()); + + data.rewind(); + while (data.position() < data.capacity()) + data.putInt(data.getInt() ^ random.nextInt()); + + data.rewind(); + while (data.position() < data.capacity()) + data.putShort((short)(data.getShort() ^ random.nextInt())); + + data.rewind(); + while (data.position() < data.capacity()) + data.putChar((char)(data.getChar() ^ random.nextInt())); + + data.rewind(); + while (data.position() < data.capacity()) { + data.putDouble(combine(data.getDouble(), random.nextLong())); + } + + data.rewind(); + while (data.position() < data.capacity()) + data.putFloat(combine(data.getFloat(), random.nextInt())); + + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 8); + data.putLong(offset, data.getLong(offset) ^ random.nextLong()); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 4); + data.putInt(offset, data.getInt(offset) ^ random.nextInt()); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 2); + data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 2); + data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 8); + data.putDouble(offset, combine(data.getDouble(offset), random.nextLong())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 4); + data.putFloat(offset, combine(data.getFloat(offset), random.nextInt())); + } + } + + // XOR the bit pattern of a double and a long, returning the + // result as a double. + // + // We convert signalling NaNs to quiet NaNs. We need to do this + // because some platforms (in particular legacy 80x87) do not + // provide transparent conversions between integer and + // floating-point types even when using raw conversions but + // quietly convert sNaN to qNaN. This causes spurious test + // failures when the template interpreter uses 80x87 and the JITs + // use XMM registers. + // + public double combine(double prev, long bits) { + bits ^= Double.doubleToRawLongBits(prev); + double result = Double.longBitsToDouble(bits); + if (Double.isNaN(result)) { + result = Double.longBitsToDouble(bits | 0x8000000000000l); + } + return result; + } + + // XOR the bit pattern of a float and an int, returning the result + // as a float. Convert sNaNs to qNaNs. + public Float combine(float prev, int bits) { + bits ^= Float.floatToRawIntBits(prev); + Float result = Float.intBitsToFloat(bits); + if (Float.isNaN(result)) { + result = Float.intBitsToFloat(bits | 0x400000); + } + return result; + } + + public void run() { + for (int i = 0; i < data.capacity(); i += 8) { + data.putLong(i, random.nextLong()); + } + + for (int i = 0; i < iterations; i++) { + step(random); + } + + if (!Arrays.equals(data.array(), data.backingArray())) { + throw new RuntimeException(); + } + } + + public static void main(String[] args) { + // The number of iterations is high to ensure that tiered + // compilation kicks in all the way up to C2. + long iterations = 100000; + if (args.length > 0) + iterations = Long.parseLong(args[0]); + + new HeapByteBufferTest(iterations).run(); + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/jsr292/MHInlineTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jsr292/MHInlineTest.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +/** + * @test + * @bug 8062280 + * @summary C2: inlining failure due to access checks being too strict + * @library /testlibrary + * @run main/othervm MHInlineTest + */ +import java.lang.invoke.*; +import com.oracle.java.testlibrary.*; +import static com.oracle.java.testlibrary.Asserts.*; + +public class MHInlineTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-XX:CompileCommand=dontinline,MHInlineTest::test*", + "MHInlineTest$Launcher"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + // The test is applicable only to C2 (present in Server VM). + if (analyzer.getStderr().contains("Server VM")) { + analyzer.shouldContain("MHInlineTest$B::public_x (3 bytes) inline (hot)"); + analyzer.shouldContain( "MHInlineTest$B::protected_x (3 bytes) inline (hot)"); + analyzer.shouldContain( "MHInlineTest$B::package_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_final_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_static_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_static_x (3 bytes) inline (hot)"); + + analyzer.shouldNotContain("MHInlineTest$A::protected_x (3 bytes) virtual call"); + analyzer.shouldNotContain("MHInlineTest$A::package_x (3 bytes) virtual call"); + } + } + + static class A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + public Class public_x() { return A.class; } + protected Class protected_x() { return A.class; } + Class package_x() { return A.class; } + final Class package_final_x() { return A.class; } + + static Class package_static_x() { return A.class; } + } + + static class B extends A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + @Override public Class public_x() { return B.class; } + @Override protected Class protected_x() { return B.class; } + @Override Class package_x() { return B.class; } + + private Class private_x() { return B.class; } + static Class private_static_x() { return B.class; } + } + + static final MethodHandle A_PUBLIC_X; + static final MethodHandle A_PROTECTED_X; + static final MethodHandle A_PACKAGE_X; + static final MethodHandle A_PACKAGE_STATIC_X; + static final MethodHandle A_PACKAGE_FINAL_X; + + static final MethodHandle B_PRIVATE_X; + static final MethodHandle B_PRIVATE_STATIC_X; + + static { + try { + MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + A_PUBLIC_X = LOOKUP.findVirtual( + A.class, "public_x", MethodType.methodType(Class.class)); + A_PROTECTED_X = LOOKUP.findVirtual( + A.class, "protected_x", MethodType.methodType(Class.class)); + A_PACKAGE_X = LOOKUP.findVirtual( + A.class, "package_x", MethodType.methodType(Class.class)); + A_PACKAGE_FINAL_X = LOOKUP.findVirtual( + A.class, "package_final_x", MethodType.methodType(Class.class)); + A_PACKAGE_STATIC_X = LOOKUP.findStatic( + A.class, "package_static_x", MethodType.methodType(Class.class)); + + B_PRIVATE_X = B.LOOKUP.findVirtual( + B.class, "private_x", MethodType.methodType(Class.class)); + B_PRIVATE_STATIC_X = B.LOOKUP.findStatic( + B.class, "private_static_x", MethodType.methodType(Class.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static final A a = new B(); + + private static void testPublicMH() { + try { + Class r = (Class)A_PUBLIC_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testProtectedMH() { + try { + Class r = (Class)A_PROTECTED_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageMH() { + try { + Class r = (Class)A_PACKAGE_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageFinalMH() { + try { + Class r = (Class)A_PACKAGE_FINAL_X.invokeExact(a); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageStaticMH() { + try { + Class r = (Class)A_PACKAGE_STATIC_X.invokeExact(); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateMH() { + try { + Class r = (Class)B_PRIVATE_X.invokeExact((B)a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateStaticMH() { + try { + Class r = (Class)B_PRIVATE_STATIC_X.invokeExact(); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + static class Launcher { + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + testPublicMH(); + } + for (int i = 0; i < 20_000; i++) { + testProtectedMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageFinalMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageStaticMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateStaticMH(); + } + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/ProdRed_Double.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Double.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Double + */ + +public class ProdRed_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + prodReductionInit(a,b); + double valid = 2000; + double total = 0; + for(int j = 0; j < 2000; j++) { + total = j + 1; + total = prodReductionImplement(a,b, total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(double[] a, double[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static double prodReductionImplement(double[] a, double[] b, double total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] - b[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/ProdRed_Float.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Float.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Float + */ + +public class ProdRed_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + prodReductionInit(a,b); + float valid = 2000; + float total = 0; + for(int j = 0; j < 2000; j++) { + total = j + 1; + total = prodReductionImplement(a,b, total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(float[] a, float[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static float prodReductionImplement(float[] a, float[] b, float total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] - b[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/ProdRed_Int.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Int.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Int + */ + +public class ProdRed_Int +{ + public static void main(String[] args) throws Exception { + int[] a = new int[256*1024]; + int[] b = new int[256*1024]; + prodReductionInit(a,b); + int valid = 419430401; + int total = 1; + for(int j = 0; j < 2000; j++) { + total = prodReductionImplement(a,b,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(int[] a, int[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static int prodReductionImplement(int[] a, int[] b, int total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] + b[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/SumRed_Double.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Double.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Double + */ + +public class SumRed_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + double[] c = new double[256*1024]; + double[] d = new double[256*1024]; + sumReductionInit(a,b,c); + double total = 0; + double valid = 3.6028590866691944E19; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + double[] a, + double[] b, + double[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static double sumReductionImplement( + double[] a, + double[] b, + double[] c, + double[] d, + double total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/SumRed_Float.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Float.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Float + */ + +public class SumRed_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + float[] c = new float[256*1024]; + float[] d = new float[256*1024]; + sumReductionInit(a,b,c); + float total = 0; + float valid = (float)4.611686E18; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + float[] a, + float[] b, + float[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static float sumReductionImplement( + float[] a, + float[] b, + float[] c, + float[] d, + float total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/loopopts/superword/SumRed_Int.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Int.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Int + */ + +public class SumRed_Int +{ + public static void main(String[] args) throws Exception { + int[] a = new int[256*1024]; + int[] b = new int[256*1024]; + int[] c = new int[256*1024]; + int[] d = new int[256*1024]; + sumReductionInit(a,b,c); + int total = 0; + int valid = 262144000; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + int[] a, + int[] b, + int[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static int sumReductionImplement( + int[] a, + int[] b, + int[] c, + int[] d, + int total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8073480 + * @summary explicit range checks should be recognized by C2 + * @library /testlibrary /../../test/lib /compiler/whitebox + * @build TestExplicitRangeChecks + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform + * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=compileonly,TestExplicitRangeChecks.test* TestExplicitRangeChecks + * + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Platform; +import sun.misc.Unsafe; + +public class TestExplicitRangeChecks { + + static int[] array = new int[10]; + + @Retention(RetentionPolicy.RUNTIME) + @interface Args { + int[] compile(); + int[] good(); + int[] bad(); + boolean deoptimize() default true; + } + + // Should be compiled as a single unsigned comparison + // 0 <= index < array.length + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test1_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // same test but so we can compile with same optimization after trap in test1_1 + static boolean test1_2(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Shouldn't matter whether first or second test is the one + // against a constants + // 0 <= index < array.length + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test2_1(int index, int[] array) { + if (index >= array.length || index < 0) { + return false; + } + return true; + } + + static boolean test2_2(int index, int[] array) { + if (index >= array.length || index < 0) { + return false; + } + return true; + } + + // 0 <= index <= array.length + @Args(compile = {5,}, good = {0, 10}, bad = {-1, 11}) + static boolean test3_1(int index, int[] array) { + if (index < 0 || index > array.length) { + return false; + } + return true; + } + + static boolean test3_2(int index, int[] array) { + if (index < 0 || index > array.length) { + return false; + } + return true; + } + + // 0 <= index <= array.length + @Args(compile = {5,}, good = {0, 10}, bad = {-1, 11}) + static boolean test4_1(int index, int[] array) { + if (index > array.length || index < 0 ) { + return false; + } + return true; + } + + static boolean test4_2(int index, int[] array) { + if (index > array.length || index < 0) { + return false; + } + return true; + } + + static int[] test5_helper(int i) { + return (i < 100) ? new int[10] : new int[5]; + } + + // 0 < index < array.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test5_1(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index <= 0 || index >= array.length) { + return false; + } + return true; + } + + static boolean test5_2(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index <= 0 || index >= array.length) { + return false; + } + return true; + } + + // 0 < index < array.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test6_1(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index >= array.length || index <= 0 ) { + return false; + } + return true; + } + + static boolean test6_2(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index >= array.length || index <= 0) { + return false; + } + return true; + } + + // 0 < index <= array.length + @Args(compile = {5,}, good = {1, 10}, bad = {0, 11}) + static boolean test7_1(int index, int[] array) { + if (index <= 0 || index > array.length) { + return false; + } + return true; + } + + static boolean test7_2(int index, int[] array) { + if (index <= 0 || index > array.length) { + return false; + } + return true; + } + + // 0 < index <= array.length + @Args(compile = {5,}, good = {1, 10}, bad = {0, 11}) + static boolean test8_1(int index, int[] array) { + if (index > array.length || index <= 0 ) { + return false; + } + return true; + } + + static boolean test8_2(int index, int[] array) { + if (index > array.length || index <= 0) { + return false; + } + return true; + } + + static int[] test9_helper1(int i) { + return (i < 100) ? new int[1] : new int[2]; + } + + static int[] test9_helper2(int i) { + return (i < 100) ? new int[10] : new int[11]; + } + + // array1.length <= index < array2.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test9_1(int index, int[] array) { + int[] array1 = test9_helper1(index); + int[] array2 = test9_helper2(index); + if (index < array1.length || index >= array2.length) { + return false; + } + return true; + } + + static boolean test9_2(int index, int[] array) { + int[] array1 = test9_helper1(index); + int[] array2 = test9_helper2(index); + if (index < array1.length || index >= array2.length) { + return false; + } + return true; + } + + // Previously supported pattern + @Args(compile = {-5,5,15}, good = {0, 9}, bad = {-1, 10}, deoptimize=false) + static boolean test10_1(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + static int[] array11 = new int[10]; + @Args(compile = {5,}, good = {0, 9}, bad = {-1,}) + static boolean test11_1(int index, int[] array) { + if (index < 0) { + return false; + } + int unused = array11[index]; + // If this one is folded with the first test then we allow + // array access above to proceed even for out of bound array + // index and the method throws an + // ArrayIndexOutOfBoundsException. + if (index >= array.length) { + return false; + } + return true; + } + + static int[] array12 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; + @Args(compile = {5,}, good = {0, 9}, bad = {-1,}) + static boolean test12_1(int index, int[] array) { + // Cannot be folded otherwise would cause incorrect array + // access if the array12 range check is executed before the + // folded test. + if (index < 0 || index >= array12[index]) { + return false; + } + return true; + } + + // Same as test1_1 but pass null array when index < 0: shouldn't + // cause NPE. + @Args(compile = {5,}, good = {0, 9}, bad = {}) + static boolean test13_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Same as test10 but with uncommon traps + @Args(compile = {5}, good = {0, 9}, bad = {-1, 10}) + static boolean test14_1(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + static boolean test14_2(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + // Same as test13_1 but pass null array: null trap should be reported on first if + @Args(compile = {5,}, good = {0, 9}, bad = {}) + static boolean test15_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Same as test1 but with no null check between the integer comparisons + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test16_1(int index, int[] array) { + int l = array.length; + if (index < 0 || index >= l) { + return false; + } + return true; + } + + static boolean test16_2(int index, int[] array) { + int l = array.length; + if (index < 0 || index >= l) { + return false; + } + return true; + } + + // Same as test1 but bound check on array access should optimize + // out. + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test17_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index] = 0; + return true; + } + + static boolean test17_2(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index] = 0; + return true; + } + + // Same as test1 but range check smearing should optimize + // 3rd range check out. + @Args(compile = {5,}, good = {}, bad = {}) + static boolean test18_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index+2] = 0; + array[index+1] = 0; + return true; + } + + static boolean test19_helper1(int index) { + if (index < 12) { + return false; + } + return true; + } + + static boolean test19_helper2(int index) { + if (index > 8) { + return false; + } + return true; + } + + // Second test should be optimized out + static boolean test19(int index, int[] array) { + test19_helper1(index); + test19_helper2(index); + return true; + } + + static boolean success = true; + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + final HashMap tests = new HashMap<>(); + { + for (Method m : this.getClass().getDeclaredMethods()) { + if (m.getName().matches("test[0-9]+(_[0-9])?")) { + assert(Modifier.isStatic(m.getModifiers())) : m; + tests.put(m.getName(), m); + } + } + } + + void doTest(String name) throws Exception { + Method m = tests.get(name + "_1"); + + Args anno = m.getAnnotation(Args.class); + int[] compile = anno.compile(); + int[] good = anno.good(); + int[] bad = anno.bad(); + boolean deoptimize = anno.deoptimize(); + + // Get compiled + for (int i = 0; i < 20000;) { + for (int j = 0; j < compile.length; j++) { + m.invoke(null, compile[j], array); + i++; + } + } + + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + "_1 not compiled"); + success = false; + } + + // check that good values don't trigger exception or + // deoptimization + for (int i = 0; i < good.length; i++) { + boolean res = (boolean)m.invoke(null, good[i], array); + + if (!res) { + System.out.println(name + " bad result for good input " + good[i]); + success = false; + } + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " deoptimized on valid access"); + success = false; + } + } + + // check that bad values trigger exception and deoptimization + for (int i = 0; i < bad.length; i++) { + if (i > 0 && deoptimize) { + m = tests.get(name + "_" + (i+1)); + for (int k = 0; k < 20000;) { + for (int j = 0; j < compile.length; j++) { + m.invoke(null, compile[j], array); + k++; + } + } + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + ("_" + (i+1)) + " not compiled"); + success = false; + } + } + + boolean res = (boolean)m.invoke(null, bad[i], array); + + if (res) { + System.out.println(name + " bad result for bad input " + bad[i]); + success = false; + } + if (Platform.isServer()) { + if (deoptimize && WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " not deoptimized on invalid access"); + success = false; + } else if (!deoptimize && !WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " deoptimized on invalid access"); + success = false; + } + } + } + + } + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } + catch (Exception e) { + throw new AssertionError(e); + } + } + + // On x64, int to long conversion should optimize away in address computation + static int test20(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += test20_helper(a, i); + } + return sum; + } + + static int test20_helper(int[] a, int i) { + if (i < 0 || i >= a.length) + throw new ArrayIndexOutOfBoundsException(); + + long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + return UNSAFE.getInt(a, address); + } + + static int test21(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += test20_helper(a, i); + } + return sum; + } + + static int test21_helper(int[] a, int i) { + if (i < 0 || i >= a.length) + throw new ArrayIndexOutOfBoundsException(); + + long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + return UNSAFE.getIntVolatile(a, address); + } + + static public void main(String[] args) throws Exception { + + if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { + throw new AssertionError("Background compilation enabled"); + } + + TestExplicitRangeChecks test = new TestExplicitRangeChecks(); + + test.doTest("test1"); + test.doTest("test2"); + test.doTest("test3"); + test.doTest("test4"); + + // pollute branch profile + for (int i = 0; i < 10000; i++) { + test5_helper((i%2 == 0) ? 0 : 1000); + } + + test.doTest("test5"); + test.doTest("test6"); + test.doTest("test7"); + test.doTest("test8"); + + // pollute branch profile + for (int i = 0; i < 10000; i++) { + test9_helper1((i%2 == 0) ? 0 : 1000); + test9_helper2((i%2 == 0) ? 0 : 1000); + } + + test.doTest("test9"); + test.doTest("test10"); + test.doTest("test11"); + test.doTest("test12"); + + test.doTest("test13"); + { + Method m = test.tests.get("test13_1"); + for (int i = 0; i < 1; i++) { + test13_1(-1, null); + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + test.doTest("test13"); + { + Method m = test.tests.get("test13_1"); + for (int i = 0; i < 10; i++) { + test13_1(-1, null); + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + + test.doTest("test14"); + + test.doTest("test15"); + { + Method m = test.tests.get("test15_1"); + for (int i = 0; i < 10; i++) { + try { + test15_1(5, null); + } catch(NullPointerException npe) {} + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + test.doTest("test15"); + test.doTest("test16"); + test.doTest("test17"); + test.doTest("test18"); + + for (int i = 0; i < 20000; i++) { + test19_helper1(20); + test19_helper2(5); + } + + { + Method m = test.tests.get("test19"); + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + } + + for (int i = 0; i < 20000; i++) { + test20(array); + } + + for (int i = 0; i < 20000; i++) { + test21(array); + } + + if (!success) { + throw new RuntimeException("some tests failed"); + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/types/TestMeetExactConstantArrays.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/types/TestMeetExactConstantArrays.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8075587 + * @summary meet of 2 constant arrays result in bottom + * @run main/othervm TestMeetExactConstantArrays + * + */ + +public class TestMeetExactConstantArrays { + public abstract static class NumbersHolder { + public Number[] getNumbers() { + return null; + } + } + + public static class IntegersHolder extends NumbersHolder { + private final static Integer integers[] = { new Integer(1) }; + + public Number[] getNumbers() { + return integers; + } + } + + public static class LongsHolder extends NumbersHolder { + private final static Long longs[] = { new Long(1) }; + + public Number[] getNumbers() { + return longs; + } + } + + public static final void loopNumbers(NumbersHolder numbersHolder) { + Number[] numbers = numbersHolder.getNumbers(); + for (int i = 0; i < numbers.length; i++) { + numbers[i].longValue(); + } + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 10000; i++) { + IntegersHolder integersHolder = new IntegersHolder(); + LongsHolder longsHolder = new LongsHolder(); + loopNumbers(integersHolder); + loopNumbers(longsHolder); + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java --- a/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Fri Apr 17 14:37:20 2015 -0700 @@ -32,12 +32,12 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -Xmixed * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method - * -XX:+IgnoreUnexpectedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot + * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot * DeoptimizeFramesTest true * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -Xmixed * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method - * -XX:+IgnoreUnexpectedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot + * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot * DeoptimizeFramesTest false * @summary testing of WB::deoptimizeFrames() */ diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/gc/arguments/TestInitialTenuringThreshold.java --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Fri Apr 17 14:37:20 2015 -0700 @@ -70,6 +70,7 @@ runWithThresholds(10, 0, true); runWithThresholds(9, 8, true); runWithThresholds(-1, 8, true); + runWithThresholds(0, -1, true); runWithThresholds(8, -1, true); runWithThresholds(16, 8, true); runWithThresholds(8, 17, true); diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestVerifyBeforeAndAfterGCFlags + * @key gc + * @bug 8000831 + * @summary Runs an simple application (GarbageProducer) with various + combinations of -XX:{+|-}Verify{After|Before}GC flags and checks that + output contain or doesn't contain expected patterns + * @modules java.management + * @library /testlibrary + * @run driver TestVerifyBeforeAndAfterGCFlags + */ + +import java.util.ArrayList; +import java.util.Collections; + +import com.oracle.java.testlibrary.Utils; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestVerifyBeforeAndAfterGCFlags { + + // VerifyBeforeGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] + public static final String VERIFY_BEFORE_GC_PATTERN = "VerifyBeforeGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + // VerifyBeforeGC: VerifyBeforeGC: VerifyBeforeGC: + public static final String VERIFY_BEFORE_GC_CORRUPTED_PATTERN = "VerifyBeforeGC:(?!\\[Verifying[^]]+\\])"; + + // VerifyAfterGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] + public static final String VERIFY_AFTER_GC_PATTERN = "VerifyAfterGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + // VerifyAfterGC: VerifyAfterGC: VerifyAfterGC: + public static final String VERIFY_AFTER_GC_CORRUPTED_PATTERN = "VerifyAfterGC:(?!\\[Verifying[^]]+\\])"; + + public static void main(String args[]) throws Exception { + String[] filteredOpts = Utils.getFilteredTestJavaOpts( + new String[] { "-Xloggc:", + "-XX:+UseGCLogFileRotation", + "-XX:-DisplayVMOutput", + "VerifyBeforeGC", + "VerifyAfterGC" }); + testVerifyFlags(false, false, filteredOpts); + testVerifyFlags(true, true, filteredOpts); + testVerifyFlags(true, false, filteredOpts); + testVerifyFlags(false, true, filteredOpts); + } + + public static void testVerifyFlags(boolean verifyBeforeGC, + boolean verifyAfterGC, + String[] opts) throws Exception { + ArrayList vmOpts = new ArrayList<>(); + if (opts != null && (opts.length > 0)) { + Collections.addAll(vmOpts, opts); + } + + Collections.addAll(vmOpts, new String[] { + "-Xmx5m", + "-Xms5m", + "-Xmn3m", + "-XX:+UnlockDiagnosticVMOptions", + (verifyBeforeGC ? "-XX:+VerifyBeforeGC" + : "-XX:-VerifyBeforeGC"), + (verifyAfterGC ? "-XX:+VerifyAfterGC" + : "-XX:-VerifyAfterGC"), + GarbageProducer.class.getName() }); + ProcessBuilder procBuilder = + ProcessTools.createJavaProcessBuilder(vmOpts.toArray( + new String[vmOpts.size()])); + OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + + analyzer.shouldHaveExitValue(0); + analyzer.shouldNotMatch(VERIFY_BEFORE_GC_CORRUPTED_PATTERN); + analyzer.shouldNotMatch(VERIFY_AFTER_GC_CORRUPTED_PATTERN); + + if (verifyBeforeGC) { + analyzer.shouldMatch(VERIFY_BEFORE_GC_PATTERN); + } else { + analyzer.shouldNotMatch(VERIFY_BEFORE_GC_PATTERN); + } + + if (verifyAfterGC) { + analyzer.shouldMatch(VERIFY_AFTER_GC_PATTERN); + } else { + analyzer.shouldNotMatch(VERIFY_AFTER_GC_PATTERN); + } + } + + public static class GarbageProducer { + static long[][] garbage = new long[10][]; + + public static void main(String args[]) { + int j = 0; + for(int i = 0; i<1000; i++) { + garbage[j] = new long[10000]; + j = (j+1)%garbage.length; + } + } + } +} diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/gc/g1/TestGCLogMessages.java --- a/hotspot/test/gc/g1/TestGCLogMessages.java Fri Apr 17 10:53:31 2015 +0200 +++ b/hotspot/test/gc/g1/TestGCLogMessages.java Fri Apr 17 14:37:20 2015 -0700 @@ -66,7 +66,6 @@ new LogMessageWithLevel("SystemDictionary Roots", Level.FINEST), new LogMessageWithLevel("CLDG Roots", Level.FINEST), new LogMessageWithLevel("JVMTI Roots", Level.FINEST), - new LogMessageWithLevel("CodeCache Roots", Level.FINEST), new LogMessageWithLevel("SATB Filtering", Level.FINEST), new LogMessageWithLevel("CM RefProcessor Roots", Level.FINEST), new LogMessageWithLevel("Wait For Strong CLD", Level.FINEST), diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/gc/g1/TestGreyReclaimedHumongousObjects.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/TestGreyReclaimedHumongousObjects.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestGreyReclaimedHumongousObjects.java + * @bug 8069367 + * @requires vm.gc == "G1" | vm.gc == "null" + * @summary Test handling of marked but unscanned reclaimed humongous objects. + * @key gc + * @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m + * -XX:+UnlockExperimentalVMOptions + * -XX:+G1EagerReclaimHumongousObjects + * -XX:+G1EagerReclaimHumongousObjectsWithStaleRefs + * TestGreyReclaimedHumongousObjects 1048576 90 + */ + +// This test spawns a bunch of threads, each of them rapidly +// allocating large objects and storing them into a circular buffer +// associated with the thread. The circular buffer results in these +// objects becoming dead in fairly short order. +// +// The situation we're trying to provoke is +// +// (1) A humongous object H is marked and added to the mark stack. +// +// (2) An evacuation pause determines H is no longer live, and +// reclaims it. This occurs before concurrent marking has gotten +// around to processing the mark stack entry for H. +// +// (3) Concurrent marking processes the mark stack entry for H. The +// bug is that it would attempt to scan the now dead object. +// +// Unfortunately, this test is *very* sensitive to configuration. +// Among the parameters that affect whether / how often we'll get into +// the desired situation within a reasonable amount of time are: +// +// - THREAD_COUNT: The number of allocating threads. +// +// - OLD_COUNT: The number of objects each thread keeps. +// +// - MAX_MEMORY: The maximum heap size. +// +// - G1HeapRegionSize +// +// - The size of the objects being allocated. +// +// The parameter values specified here: +// +// - THREAD_COUNT = 12 +// - OLD_COUNT == 4 +// - MAX_MEMORY == 128m +// - G1HeapRegionSize = 1m +// - Object size = 1048576 (2 regions after header overhead and roundup) +// +// seems to work well at provoking the desired state fairly quickly. +// Even relatively small perturbations may change that. The key +// factors seem to be keeping the heap mostly full of live objects but +// having them become dead fairly quickly. + +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +public class TestGreyReclaimedHumongousObjects { + + static class NamedThreadFactory implements ThreadFactory { + private int threadNum = 0; + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, THREAD_NAME + (threadNum++)); + } + } + + static class Runner extends Thread { + private final Date startDate = new Date(); + private final int obj_size; + private final Object[] old_garbage; + private int old_index = 0; + + public Runner(int obj_size) { + this.obj_size = obj_size; + old_garbage = new Object[OLD_COUNT]; + } + + private void allocate_garbage() { + byte[] garbage = new byte[obj_size]; + old_garbage[Math.abs(++old_index % OLD_COUNT)] = garbage; + } + + @Override + public void run() { + try { + while (!isInterrupted()) { + allocate_garbage(); + Thread.sleep(0); // Yield, to ensure interruptable. + } + } catch (InterruptedException e) { + System.out.println("Aborted after " + + (new Date().getTime() - startDate.getTime()) + + " ms"); + interrupt(); + } + } + } + + public static void main(String[] args) throws Exception { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + + System.out.println("Max memory= " + MAX_MEMORY + " bytes"); + + int obj_size = 0; + long seconds_to_run = 0; + if (args.length != 2) { + throw new RuntimeException("Object size argument must be supplied"); + } else { + obj_size = Integer.parseInt(args[0]); + seconds_to_run = Integer.parseInt(args[1]); + } + System.out.println("Objects size= " + obj_size + " bytes"); + System.out.println("Seconds to run=" + seconds_to_run); + + int region_size = + Integer.parseInt(diagnostic.getVMOption("G1HeapRegionSize").getValue()); + if (obj_size < (region_size / 2)) { + throw new RuntimeException("Object size " + obj_size + + " is not humongous with region size " + region_size); + } + + ExecutorService executor = + Executors.newFixedThreadPool(THREAD_COUNT, new NamedThreadFactory()); + System.out.println("Starting " + THREAD_COUNT + " threads"); + + for (int i = 0; i < THREAD_COUNT; i++) { + executor.execute(new Runner(obj_size)); + } + + Thread.sleep(seconds_to_run * 1000); + executor.shutdownNow(); + + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + System.err.println("Thread pool did not terminate after 10 seconds after shutdown"); + } + } + + private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + private static final int OLD_COUNT = 4; + private static final int THREAD_COUNT = 12; + private static final String THREAD_NAME = "TestGreyRH-"; +} + diff -r 9925b07bba5b -r 5c6dacbd17ae hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Fri Apr 17 14:37:20 2015 -0700 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestLargePageUseForAuxMemory.java + * @bug 8058354 + * @key gc + * @library /testlibrary /../../test/lib + * @requires (vm.gc=="G1" | vm.gc=="null") + * @build TestLargePageUseForAuxMemory + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @summary Test that auxiliary data structures are allocated using large pages if available. + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class TestLargePageUseForAuxMemory { + static final int HEAP_REGION_SIZE = 4 * 1024 * 1024; + static long largePageSize; + static long smallPageSize; + + static void checkSmallTables(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Block offset table': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Card counts table': pg_sz=" + expectedPageSize); + } + + static void checkBitmaps(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Prev Bitmap': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Next Bitmap': pg_sz=" + expectedPageSize); + } + + static void testVM(long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception { + ProcessBuilder pb; + // Test with large page enabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:+UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, (cardsShouldUseLargePages ? largePageSize : smallPageSize)); + checkBitmaps(output, (bitmapShouldUseLargePages ? largePageSize : smallPageSize)); + output.shouldHaveExitValue(0); + + // Test with large page disabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:-UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, smallPageSize); + checkBitmaps(output, smallPageSize); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + if (!Platform.isDebugBuild()) { + System.out.println("Skip tests on non-debug builds because the required option TracePageSizes is a debug-only option."); + return; + } + + WhiteBox wb = WhiteBox.getWhiteBox(); + smallPageSize = wb.getVMPageSize(); + largePageSize = wb.getVMLargePageSize(); + + if (largePageSize == 0) { + System.out.println("Skip tests because large page support does not seem to be available on this platform."); + return; + } + + // To get large pages for the card table etc. we need at least a 1G heap (with 4k page size). + // 32 bit systems will have problems reserving such an amount of contiguous space, so skip the + // test there. + if (!Platform.is32bit()) { + // Size that a single card covers. + final int cardSize = 512; + + final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize; + + testVM(heapSizeForCardTableUsingLargePages, true, true); + testVM(heapSizeForCardTableUsingLargePages + HEAP_REGION_SIZE, true, true); + testVM(heapSizeForCardTableUsingLargePages - HEAP_REGION_SIZE, false, true); + } + + // Minimum heap requirement to get large pages for bitmaps is 128M heap. This seems okay to test + // everywhere. + final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte + final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor; + + testVM(heapSizeForBitmapUsingLargePages, false, true); + testVM(heapSizeForBitmapUsingLargePages + HEAP_REGION_SIZE, false, true); + testVM(heapSizeForBitmapUsingLargePages - HEAP_REGION_SIZE, false, false); + } +} +