# HG changeset patch # User trims # Date 1213741625 25200 # Node ID 4f91c08b3e4498213a9c5a24898f7d9c38cf86fb # Parent abe7181cbe8a05eb05b263126c99136028c123e0# Parent 44a553b2809d6da2945f7a0fb4793a1c05326c6c Merge diff -r abe7181cbe8a -r 4f91c08b3e44 agent/make/Makefile --- a/agent/make/Makefile Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/make/Makefile Tue Jun 17 15:27:05 2008 -0700 @@ -246,16 +246,16 @@ all: filelist @mkdir -p $(OUTPUT_DIR) @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - @javac -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist - @rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer + @${JDK_HOME}/bin/javac -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist + @${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql allprof: filelist @mkdir -p $(OUTPUT_DIR) @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - @javac -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist - @rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer + @${JDK_HOME}/bin/javac -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist + @${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/HSDB.java --- a/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Tue Jun 17 15:27:05 2008 -0700 @@ -398,7 +398,7 @@ frame.getContentPane().add(desktop); GraphicsUtilities.reshapeToAspectRatio(frame, 4.0f/3.0f, 0.75f, Toolkit.getDefaultToolkit().getScreenSize()); GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize()); - frame.show(); + frame.setVisible(true); Runtime.getRuntime().addShutdownHook(new java.lang.Thread() { public void run() { diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java --- a/agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java Tue Jun 17 15:27:05 2008 -0700 @@ -148,7 +148,7 @@ } try { - return file.toURL(); + return file.toURI().toURL(); } catch (MalformedURLException mue) { throw new InternalError(mue.getMessage()); } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java Tue Jun 17 15:27:05 2008 -0700 @@ -47,6 +47,6 @@ 4.0f/3.0f, 0.85f, Toolkit.getDefaultToolkit().getScreenSize()); GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize()); - frame.show(); + frame.setVisible(true); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java Tue Jun 17 15:27:05 2008 -0700 @@ -78,7 +78,7 @@ this(parent); this.classPathSet = true; try { - addURL(new File(classPath).toURL()); + addURL(new File(classPath).toURI().toURL()); } catch(MalformedURLException mue) { throw new RuntimeException(mue); } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java Tue Jun 17 15:27:05 2008 -0700 @@ -0,0 +1,59 @@ +/* + * @(#)BinaryTreeDictionary.java + * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.runtime.*; + +public class BinaryTreeDictionary extends VMObject { + 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("BinaryTreeDictionary"); + totalSizeField = type.getCIntegerField("_totalSize"); + } + + // Fields + private static CIntegerField totalSizeField; + + // Accessors + public long size() { + return totalSizeField.getValue(addr); + } + + // Constructor + public BinaryTreeDictionary(Address addr) { + super(addr); + } +} diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Tue Jun 17 15:27:05 2008 -0700 @@ -35,6 +35,20 @@ public class CompactibleFreeListSpace extends CompactibleSpace { private static AddressField collectorField; + // for free size, three fields + // FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks + // FreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks + // LinearAllocBlock _smallLinearAllocBlock; // small linear alloc in TLAB + private static AddressField indexedFreeListField; + private static AddressField dictionaryField; + private static long smallLinearAllocBlockFieldOffset; + private static long indexedFreeListSizeOf; + + private int heapWordSize; // 4 for 32bit, 8 for 64 bits + private int IndexSetStart; // for small indexed list + private int IndexSetSize; + private int IndexSetStride; + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -51,10 +65,26 @@ Type type = db.lookupType("CompactibleFreeListSpace"); collectorField = type.getAddressField("_collector"); + collectorField = type.getAddressField("_collector"); + dictionaryField = type.getAddressField("_dictionary"); + indexedFreeListField = type.getAddressField("_indexedFreeList[0]"); + smallLinearAllocBlockFieldOffset = type.getField("_smallLinearAllocBlock").getOffset(); } public CompactibleFreeListSpace(Address addr) { super(addr); + if ( VM.getVM().isLP64() ) { + heapWordSize = 8; + IndexSetStart = 1; + IndexSetStride = 1; + } + else { + heapWordSize = 4; + IndexSetStart = 2; + IndexSetStride = 2; + } + + IndexSetSize = 257; } // Accessing block offset table @@ -62,9 +92,17 @@ return (CMSCollector) VMObjectFactory.newObject( CMSCollector.class, collectorField.getValue(addr)); - } + } + + public long free0() { + return capacity() - used0(); + } public long used() { + return capacity() - free(); + } + + public long used0() { List regions = getLiveRegions(); long usedSize = 0L; for (Iterator itr = regions.iterator(); itr.hasNext();) { @@ -75,11 +113,41 @@ } public long free() { - return capacity() - used(); - } + // small chunks + long size = 0; + Address cur = addr.addOffsetTo( indexedFreeListField.getOffset() ); + cur = cur.addOffsetTo(IndexSetStart*FreeList.sizeOf()); + for (int i=IndexSetStart; i> cmsShift, cmsMask) & 0x1L) == 0x1L; + } + public long getSize() { return (long)(value() >> sizeShift); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Tue Jun 17 15:27:05 2008 -0700 @@ -274,10 +274,10 @@ // hc_klass is a HotSpot magic field and hence we can't // find it from InstanceKlass for java.lang.Class. TypeDataBase db = VM.getVM().getTypeDataBase(); - int hcKlassOffset = (int) Oop.getHeaderSize(); + int hcKlassOffset = (int) Instance.getHeaderSize(); try { hcKlassOffset += (db.lookupIntConstant("java_lang_Class::hc_klass_offset").intValue() * - db.getAddressSize()); + VM.getVM().getHeapOopSize()); } catch (RuntimeException re) { // ignore, currently java_lang_Class::hc_klass_offset is zero } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java Tue Jun 17 15:27:05 2008 -0700 @@ -648,6 +648,6 @@ System.exit(0); } }); - frame.show(); + frame.setVisible(true); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java Tue Jun 17 15:27:05 2008 -0700 @@ -220,7 +220,7 @@ } }); frame.setSize(500, 500); - frame.show(); + frame.setVisible(true); panel.requestFocus(); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java Tue Jun 17 15:27:05 2008 -0700 @@ -226,7 +226,7 @@ } }); frame.setSize(500, 500); - frame.show(); + frame.setVisible(true); panel.requestFocus(); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java Tue Jun 17 15:27:05 2008 -0700 @@ -424,7 +424,7 @@ } }); frame.getContentPane().add(hpsb); - frame.show(); + frame.setVisible(true); } } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java Tue Jun 17 15:27:05 2008 -0700 @@ -43,7 +43,7 @@ public void setVisible(boolean visible) { frame.setVisible(visible); } public void setSize(int x, int y) { frame.setSize(x, y); } public void pack() { frame.pack(); } - public void show() { frame.show(); } + public void show() { frame.setVisible(true); } public void dispose() { frame.dispose(); } public void setBackground(Color color) { frame.setBackground(color); } public void setResizable(boolean resizable) { frame.setResizable(resizable); } diff -r abe7181cbe8a -r 4f91c08b3e44 agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java Tue Jun 10 10:22:49 2008 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java Tue Jun 17 15:27:05 2008 -0700 @@ -477,9 +477,9 @@ static class TreeTableTextField extends JTextField { public int offset; - public void reshape(int x, int y, int w, int h) { + public void setBounds(int x, int y, int w, int h) { int newX = Math.max(x, offset); - super.reshape(newX, y, w - (newX - x), h); + super.setBounds(newX, y, w - (newX - x), h); } } diff -r abe7181cbe8a -r 4f91c08b3e44 make/hotspot_version --- a/make/hotspot_version Tue Jun 10 10:22:49 2008 -0700 +++ b/make/hotspot_version Tue Jun 17 15:27:05 2008 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=13 HS_MINOR_VER=0 -HS_BUILD_NUMBER=01 +HS_BUILD_NUMBER=02 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r abe7181cbe8a -r 4f91c08b3e44 make/jprt.config --- a/make/jprt.config Tue Jun 10 10:22:49 2008 -0700 +++ b/make/jprt.config Tue Jun 17 15:27:05 2008 -0700 @@ -68,8 +68,23 @@ solaris_arch=i386 fi - # Get the SS11 compilers into path (make sure it matches ALT setting) - compiler_path=${slashjava}/devtools/${solaris_arch}/SUNWspro/SS11/bin + if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then + compiler_name=${JPRT_SOLARIS_COMPILER_NAME} + else + if [ "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6" -o \ + "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6u10" -o \ + "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6perf" ] ; then + # All jdk6 builds use SS11 + compiler_name=SS11 + else + # FIXUP: Change to SS12 once it has been validated. + #compiler_name=SS12 + compiler_name=SS11 + fi + fi + + # Get into path (make sure it matches ALT setting) + compiler_path=${slashjava}/devtools/${solaris_arch}/SUNWspro/${compiler_name}/bin dirMustExist "${compiler_path}" COMPILER_PATH path4sdk=${compiler_path} diff -r abe7181cbe8a -r 4f91c08b3e44 make/jprt.properties --- a/make/jprt.properties Tue Jun 10 10:22:49 2008 -0700 +++ b/make/jprt.properties Tue Jun 17 15:27:05 2008 -0700 @@ -24,209 +24,274 @@ # Properties for jprt -JPRT.tools.default.release=jdk1.7.0 +# All build result bundles are full jdks, so the 64bit testing does not +# need the 32bit sibling bundle installed. +# Note: If the hotspot/make/Makefile changed to only bundle the 64bit files +# when bundling 64bit, and stripped out the 64bit files from any 32bit +# bundles, then this setting would be need to be "true". + +jprt.need.sibling.build=false + +# At submit time, the release supplied will be in jprt.submit.release +# and will be one of the official release names defined in jprt. +# jprt supports property value expansion using ${property.name} syntax. -# Build result bundles are not partial builds| but include everything -JPRT.need.sibling.build=false +# This tells jprt what default release we want to build + +jprt.tools.default.release=${jprt.submit.release} + +# Define the Solaris platforms we want for the various releases + +jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 +jprt.my.solaris.sparc.jdk6=solaris_sparc_5.8 +jprt.my.solaris.sparc.jdk6perf=solaris_sparc_5.8 +jprt.my.solaris.sparc.jdk6u10=solaris_sparc_5.8 +jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} -# Directories needed to build -JPRT.bundle.src.dirs=make src agent -JPRT.bundle.exclude.src.dirs=build +jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 +jprt.my.solaris.sparcv9.jdk6=solaris_sparcv9_5.8 +jprt.my.solaris.sparcv9.jdk6perf=solaris_sparcv9_5.8 +jprt.my.solaris.sparcv9.jdk6u10=solaris_sparcv9_5.8 +jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} + +jprt.my.solaris.i586.jdk7=solaris_i586_5.10 +jprt.my.solaris.i586.jdk6=solaris_i586_5.8 +jprt.my.solaris.i586.jdk6perf=solaris_i586_5.8 +jprt.my.solaris.i586.jdk6u10=solaris_i586_5.8 +jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} +jprt.my.solaris.x64.jdk7=solaris_x64_5.10 +jprt.my.solaris.x64.jdk6=solaris_x64_5.10 +jprt.my.solaris.x64.jdk6perf=solaris_x64_5.10 +jprt.my.solaris.x64.jdk6u10=solaris_x64_5.10 +jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} + +jprt.my.linux.i586=linux_i586 +jprt.my.linux.x64=linux_x64 +jprt.my.windows.i586=windows_i586 +jprt.my.windows.x64=windows_x64 + +# Standard list of jprt build targets for this source tree + +jprt.build.targets= \ + ${jprt.my.solaris.sparc}-{product|fastdebug|debug}, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug|debug}, \ + ${jprt.my.solaris.i586}-{product|fastdebug|debug}, \ + ${jprt.my.solaris.x64}-{product|fastdebug|debug}, \ + ${jprt.my.linux.i586}-{product|fastdebug|debug}, \ + ${jprt.my.linux.x64}-{product|fastdebug}, \ + ${jprt.my.windows.i586}-{product|fastdebug|debug}, \ + ${jprt.my.windows.x64}-{product|fastdebug|debug} -# Standard list of JPRT build targets for this workspace -JPRT.build.targets= \ - solaris_sparc_5.10-{product|fastdebug|debug}, \ - solaris_sparcv9_5.10-{product|fastdebug|debug}, \ - solaris_i586_5.10-{product|fastdebug|debug}, \ - solaris_x64_5.10-{product|fastdebug|debug}, \ - linux_i586-{product|fastdebug|debug}, \ - linux_x64-{product|fastdebug}, \ - windows_i586-{product|fastdebug|debug}, \ - windows_x64-{product|fastdebug|debug} +# Subset lists of test targets for this source tree + +jprt.my.solaris.sparc.test.targets= \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ + ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ + ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp, \ + ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_2, \ + ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_3, \ + ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_default, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_SerialGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParallelGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParNewGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_CMS, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_3 + +jprt.my.solaris.sparcv9.test.targets= \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ + ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ + ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp, \ + ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_2, \ + ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_3, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_default, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_SerialGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParallelGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParNewGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_3 -# Standard list of JPRT test targets for this workspace -JPRT.test.targets = \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-jvm98, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-scimark, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-jvm98, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-scimark, \ - solaris_i586_5.10-{product|fastdebug}-{c1|c2}-jvm98, \ - solaris_i586_5.10-{product|fastdebug}-{c1|c2}-scimark, \ - solaris_x64_5.10-{product|fastdebug}-c2-jvm98, \ - solaris_x64_5.10-{product|fastdebug}-c2-scimark, \ - linux_i586-{product|fastdebug}-{c1|c2}-jvm98, \ - linux_i586-{product|fastdebug}-{c1|c2}-scimark, \ - linux_x64-{product|fastdebug}-c2-jvm98, \ - linux_x64-{product|fastdebug}-c2-scimark, \ - windows_i586-{product|fastdebug}-{c1|c2}-jvm98, \ - windows_i586-{product|fastdebug}-{c1|c2}-scimark, \ - windows_x64-{product|fastdebug}-c2-jvm98, \ - windows_x64-{product|fastdebug}-c2-scimark, \ - solaris_sparc_5.10-product-{c1|c2}-runThese, \ - solaris_sparc_5.10-product-{c1|c2}-runThese_Xcomp, \ - solaris_sparc_5.10-product-{c1|c2}-runThese_Xcomp_2, \ - solaris_sparc_5.10-product-{c1|c2}-runThese_Xcomp_3, \ - solaris_sparc_5.10-fastdebug-c1-runThese_Xshare, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_default, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_default_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCBasher_CMS_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCOld_default, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCOld_SerialGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCOld_ParallelGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCOld_ParNewGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-GCOld_CMS, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-jbb_default, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-jbb_CMS, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-scimark_2, \ - solaris_sparc_5.10-{product|fastdebug}-{c1|c2}-scimark_3, \ - solaris_sparcv9_5.10-product-c2-runThese, \ - solaris_sparcv9_5.10-product-c2-runThese_Xcomp, \ - solaris_sparcv9_5.10-product-c2-runThese_Xcomp_2, \ - solaris_sparcv9_5.10-product-c2-runThese_Xcomp_3, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_default, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_SerialGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_CMS, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_default_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCBasher_CMS_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCOld_default, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCOld_SerialGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCOld_ParallelGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCOld_ParNewGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-GCOld_CMS, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-jbb_default, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-jbb_SerialGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-jbb_ParallelGC, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-jbb_CMS, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-scimark_2, \ - solaris_sparcv9_5.10-{product|fastdebug}-c2-scimark_3, \ - solaris_x64-product-c2-runThese, \ - solaris_x64-product-c2-runThese_Xcomp, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_default, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_SerialGC, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_CMS, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_default_2, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - solaris_x64-{product|fastdebug}-c2-GCBasher_CMS_2, \ - solaris_x64-{product|fastdebug}-c2-GCOld_default, \ - solaris_x64-{product|fastdebug}-c2-GCOld_SerialGC, \ - solaris_x64-{product|fastdebug}-c2-GCOld_ParallelGC, \ - solaris_x64-{product|fastdebug}-c2-GCOld_ParNewGC, \ - solaris_x64-{product|fastdebug}-c2-GCOld_CMS, \ - solaris_x64-{product|fastdebug}-c2-jbb_default, \ - solaris_x64-{product|fastdebug}-c2-jbb_SerialGC, \ - solaris_x64-{product|fastdebug}-c2-jbb_ParallelGC, \ - solaris_x64-{product|fastdebug}-c2-jbb_CMS, \ - solaris_i586_5.10-product-{c1|c2}-runThese_Xcomp, \ - solaris_i586_5.10-product-c2-runThese_Xcomp_2, \ - solaris_i586_5.10-fastdebug-c1-runThese_Xcomp_2, \ - solaris_i586_5.10-fastdebug-c1-runThese_Xshare, \ - solaris_i586_5.10-product-c1-GCBasher_default, \ - solaris_i586_5.10-product-c1-GCBasher_SerialGC, \ - solaris_i586_5.10-product-c1-GCBasher_ParallelGC, \ - solaris_i586_5.10-product-c1-GCBasher_ParNewGC, \ - solaris_i586_5.10-product-c1-GCBasher_CMS, \ - solaris_i586_5.10-fastdebug-c2-GCBasher_default, \ - solaris_i586_5.10-fastdebug-c2-GCBasher_SerialGC, \ - solaris_i586_5.10-fastdebug-c2-GCBasher_ParallelGC, \ - solaris_i586_5.10-fastdebug-c2-GCBasher_ParNewGC, \ - solaris_i586_5.10-fastdebug-c2-GCBasher_CMS, \ - solaris_i586_5.10-product-c1-GCOld_default, \ - solaris_i586_5.10-product-c1-GCOld_SerialGC, \ - solaris_i586_5.10-product-c1-GCOld_ParallelGC, \ - solaris_i586_5.10-product-c1-GCOld_ParNewGC, \ - solaris_i586_5.10-product-c1-GCOld_CMS, \ - solaris_i586_5.10-fastdebug-c2-jbb_default, \ - solaris_i586_5.10-fastdebug-c2-jbb_ParallelGC, \ - solaris_i586_5.10-fastdebug-c2-jbb_CMS, \ - solaris_i586_5.10-{product|fastdebug}-{c1|c2}-scimark_2, \ - solaris_i586_5.10-{product|fastdebug}-{c1|c2}-scimark_3, \ - linux_i586-product-c1-runThese_Xcomp, \ - linux_i586-product-c1-runThese_Xcomp_2, \ - linux_i586-product-c1-runThese_Xcomp_3, \ - linux_i586-fastdebug-c1-runThese_Xshare, \ - linux_i586-fastdebug-c2-runThese_Xcomp, \ - linux_i586-fastdebug-c2-runThese_Xcomp_2, \ - linux_i586-{product|fastdebug}-{c1|c2}-GCBasher_default, \ - linux_i586-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - linux_i586-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - linux_i586-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - linux_i586-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - linux_i586-product-{c1|c2}-GCOld_default, \ - linux_i586-product-{c1|c2}-GCOld_SerialGC, \ - linux_i586-product-{c1|c2}-GCOld_ParallelGC, \ - linux_i586-product-{c1|c2}-GCOld_ParNewGC, \ - linux_i586-product-{c1|c2}-GCOld_CMS, \ - linux_i586-{product|fastdebug}-c1-jbb_default, \ - linux_i586-{product|fastdebug}-c1-jbb_ParallelGC, \ - linux_i586-{product|fastdebug}-c1-jbb_CMS, \ - linux_i586-{product|fastdebug}-c2-scimark_2, \ - linux_i586-{product|fastdebug}-c2-scimark_3, \ - linux_x64-{product|fastdebug}-c2-GCBasher_default, \ - linux_x64-{product|fastdebug}-c2-GCBasher_SerialGC, \ - linux_x64-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - linux_x64-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - linux_x64-{product|fastdebug}-c2-GCBasher_CMS, \ - linux_x64-{product|fastdebug}-c2-GCOld_default, \ - linux_x64-{product|fastdebug}-c2-GCOld_SerialGC, \ - linux_x64-{product|fastdebug}-c2-GCOld_ParallelGC, \ - linux_x64-{product|fastdebug}-c2-GCOld_ParNewGC, \ - linux_x64-{product|fastdebug}-c2-GCOld_CMS, \ - linux_x64-{product|fastdebug}-c2-jbb_default, \ - linux_x64-{product|fastdebug}-c2-jbb_ParallelGC, \ - linux_x64-{product|fastdebug}-c2-scimark_2, \ - linux_x64-{product|fastdebug}-c2-scimark_3, \ - windows_i586-product-{c1|c2}-runThese, \ - windows_i586-product-{c1|c2}-runThese_Xcomp, \ - windows_i586-fastdebug-c1-runThese_Xshare, \ - windows_i586-{product|fastdebug}-{c1|c2}-GCBasher_default, \ - windows_i586-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - windows_i586-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - windows_i586-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - windows_i586-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - windows_i586-product-{c1|c2}-GCOld_default, \ - windows_i586-product-{c1|c2}-GCOld_SerialGC, \ - windows_i586-product-{c1|c2}-GCOld_ParallelGC, \ - windows_i586-product-{c1|c2}-GCOld_ParNewGC, \ - windows_i586-product-{c1|c2}-GCOld_CMS, \ - windows_i586-{product|fastdebug}-{c1|c2}-jbb_default, \ - windows_i586-product-{c1|c2}-jbb_ParallelGC, \ - windows_i586-product-{c1|c2}-jbb_CMS, \ - windows_i586-product-{c1|c2}-scimark_2, \ - windows_i586-product-{c1|c2}-scimark_3, \ - windows_x64-product-c2-runThese, \ - windows_x64-product-c2-runThese_Xcomp, \ - windows_x64-{product|fastdebug}-c2-GCBasher_default, \ - windows_x64-{product|fastdebug}-c2-GCBasher_SerialGC, \ - windows_x64-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - windows_x64-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - windows_x64-{product|fastdebug}-c2-GCBasher_CMS, \ - windows_x64-{product|fastdebug}-c2-GCOld_default, \ - windows_x64-{product|fastdebug}-c2-GCOld_SerialGC, \ - windows_x64-{product|fastdebug}-c2-GCOld_ParallelGC, \ - windows_x64-{product|fastdebug}-c2-GCOld_ParNewGC, \ - windows_x64-{product|fastdebug}-c2-GCOld_CMS, \ - windows_x64-{product|fastdebug}-c2-jbb_default, \ - windows_x64-product-c2-jbb_CMS, \ - windows_x64-product-c2-jbb_ParallelGC, \ - windows_x64-{product|fastdebug}-c2-scimark_2, \ - windows_x64-{product|fastdebug}-c2-scimark_3 +jprt.my.solaris.x64.test.targets= \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-scimark, \ + ${jprt.my.solaris.x64}-product-c2-runThese, \ + ${jprt.my.solaris.x64}-product-c2-runThese_Xcomp, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_default, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_default_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_default, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_CMS + +jprt.my.solaris.i586.test.targets= \ + ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ + ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ + ${jprt.my.solaris.i586}-product-c2-runThese_Xcomp_2, \ + ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp_2, \ + ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xshare, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_default, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_SerialGC, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_ParallelGC, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_ParNewGC, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_default, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_SerialGC, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParallelGC, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParNewGC, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_default, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_SerialGC, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_ParallelGC, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_ParNewGC, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_CMS, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ + ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_2, \ + ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_3 +jprt.my.linux.i586.test.targets = \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ + ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ + ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_2, \ + ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_3, \ + ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ + ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp, \ + ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp_2, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_default, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_SerialGC, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParallelGC, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParNewGC, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_2, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_3 + +jprt.my.linux.x64.test.targets = \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_default, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_default, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_2, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_3 + +jprt.my.windows.i586.test.targets = \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-scimark, \ + ${jprt.my.windows.i586}-product-{c1|c2}-runThese, \ + ${jprt.my.windows.i586}-product-{c1|c2}-runThese_Xcomp, \ + ${jprt.my.windows.i586}-fastdebug-c1-runThese_Xshare, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_default, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_SerialGC, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParallelGC, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParNewGC, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ + ${jprt.my.windows.i586}-product-{c1|c2}-scimark_2, \ + ${jprt.my.windows.i586}-product-{c1|c2}-scimark_3 + +jprt.my.windows.x64.test.targets = \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark, \ + ${jprt.my.windows.x64}-product-c2-runThese, \ + ${jprt.my.windows.x64}-product-c2-runThese_Xcomp, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_default, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_default, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ + ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_2, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_3 + +# The complete list of test targets for jprt + +jprt.test.targets = \ + ${jprt.my.solaris.sparc.test.targets}, \ + ${jprt.my.solaris.sparcv9.test.targets}, \ + ${jprt.my.solaris.i586.test.targets}, \ + ${jprt.my.solaris.x64.test.targets}, \ + ${jprt.my.linux.i586.test.targets}, \ + ${jprt.my.linux.x64.test.targets}, \ + ${jprt.my.windows.i586.test.targets}, \ + ${jprt.my.windows.x64.test.targets} + diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/amd64.make --- a/make/solaris/makefiles/amd64.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/amd64.make Tue Jun 17 15:27:05 2008 -0700 @@ -45,10 +45,6 @@ OPT_CFLAGS/generateOptoStub.o = -xO2 OPT_CFLAGS/thread.o = -xO2 -# Work around for 6624782 -OPT_CFLAGS/instanceKlass.o = -Qoption ube -no_a2lf -OPT_CFLAGS/objArrayKlass.o = -Qoption ube -no_a2lf - else ifeq ("${Platform_compiler}", "gcc") diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/debug.make --- a/make/solaris/makefiles/debug.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/debug.make Tue Jun 17 15:27:05 2008 -0700 @@ -29,7 +29,8 @@ DEBUG_CFLAGS/BYFILE = $(DEBUG_CFLAGS/$@)$(DEBUG_CFLAGS/DEFAULT$(DEBUG_CFLAGS/$@)) ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \>= 5.8), 1) + +ifeq ($(COMPILER_REV),5.8) # SS11 SEGV when compiling with -g and -xarch=v8, using different backend DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0 DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0 diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/dtrace.make --- a/make/solaris/makefiles/dtrace.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/dtrace.make Tue Jun 17 15:27:05 2008 -0700 @@ -92,12 +92,12 @@ $(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ - $(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. -I$(GENERATED) \ + $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc $(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ - $(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. \ + $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor endif # ifneq ("${ISA}","${BUILDARCH}") diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/fastdebug.make --- a/make/solaris/makefiles/fastdebug.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/fastdebug.make Tue Jun 17 15:27:05 2008 -0700 @@ -25,7 +25,7 @@ # Sets make macros for making debug version of VM # Compiler specific DEBUG_CFLAGS are passed in from gcc.make, sparcWorks.make -# They may also specify FASTDEBUG_CFLAGS, but it defaults to DEBUG_FLAGS. +# They may also specify FASTDEBUG_CFLAGS, but it defaults to DEBUG_CFLAGS. FASTDEBUG_CFLAGS$(FASTDEBUG_CFLAGS) = $(DEBUG_CFLAGS) @@ -35,15 +35,26 @@ ifeq ("${Platform_compiler}", "sparcWorks") OPT_CFLAGS/SLOWER = -xO2 -ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1) -# CC 5.5 has bug 4908364 with -xO4 + +# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) +ifeq ($(COMPILER_REV), 5.9) + # Not clear this workaround could be skipped in some cases. + OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) + OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) + OPT_CFLAGS/jni.o = $(OPT_CFLAGS/SLOWER) +endif + +ifeq ($(COMPILER_REV), 5.5) +# CC 5.5 has bug 4908364 with -xO4 (Fixed in 5.6) OPT_CFLAGS/library_call.o = $(OPT_CFLAGS/SLOWER) -else # COMPILER_REV >= 5.5 +endif # COMPILER_REV == 5.5 + +ifeq ($(shell expr $(COMPILER_REV) \<= 5.4), 1) # Compilation of *_.cpp can take an hour or more at O3. Use O2 # See comments at top of sparc.make. OPT_CFLAGS/ad_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER) OPT_CFLAGS/dfa_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER) -endif # COMPILER_REV >= 5.5 +endif # COMPILER_REV <= 5.4 ifeq (${COMPILER_REV}, 5.0) # Avoid a compiler bug caused by using -xO -g diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/jvmg.make --- a/make/solaris/makefiles/jvmg.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/jvmg.make Tue Jun 17 15:27:05 2008 -0700 @@ -29,7 +29,8 @@ DEBUG_CFLAGS/BYFILE = $(DEBUG_CFLAGS/$@)$(DEBUG_CFLAGS/DEFAULT$(DEBUG_CFLAGS/$@)) ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \>= 5.8), 1) + +ifeq ($(COMPILER_REV),5.8)) # SS11 SEGV when compiling with -g and -xarch=v8, using different backend DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0 DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0 diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/optimized.make --- a/make/solaris/makefiles/optimized.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/optimized.make Tue Jun 17 15:27:05 2008 -0700 @@ -30,12 +30,21 @@ OPT_CFLAGS/BYFILE = $(OPT_CFLAGS/$@)$(OPT_CFLAGS/DEFAULT$(OPT_CFLAGS/$@)) # (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files) +ifeq ("${Platform_compiler}", "sparcWorks") -# Workaround SS11 bug 6345274 (all platforms) -ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \>= 5.8), 1) +# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) +ifeq ($(COMPILER_REV),5.9) + # Not clear this workaround could be skipped in some cases. + OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g + OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g + OPT_CFLAGS/jni.o = $(OPT_CFLAGS/SLOWER) -g +endif + +# Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12) +ifeq ($(COMPILER_REV),5.8)) OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2) -endif # COMPILER_REV >= 5.8 +endif # COMPILER_REV == 5.8 + endif # Platform_compiler == sparcWorks # If you set HOTSPARC_GENERIC=yes, you disable all OPT_CFLAGS settings diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/product.make --- a/make/solaris/makefiles/product.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/product.make Tue Jun 17 15:27:05 2008 -0700 @@ -38,12 +38,21 @@ endif # (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files) +ifeq ("${Platform_compiler}", "sparcWorks") -# Workaround SS11 bug 6345274 (all platforms) -ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \>= 5.8), 1) +# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) +ifeq ($(COMPILER_REV),5.9) + # Not clear this workaround could be skipped in some cases. + OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g + OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g + OPT_CFLAGS/jni.o = $(OPT_CFLAGS/SLOWER) -g +endif + +# Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12) +ifeq ($(COMPILER_REV),5.8) OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2) -endif # COMPILER_REV >= 5.8 +endif # COMPILER_REV == 5.8 + endif # Platform_compiler == sparcWorks # If you set HOTSPARC_GENERIC=yes, you disable all OPT_CFLAGS settings diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/sparc.make --- a/make/solaris/makefiles/sparc.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/sparc.make Tue Jun 17 15:27:05 2008 -0700 @@ -23,7 +23,7 @@ # Obj_Files += solaris_sparc.o -ASFLAGS += $(ARCHFLAG) +ASFLAGS += $(AS_ARCHFLAG) ifeq ("${Platform_compiler}", "sparcWorks") ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1) diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/sparcWorks.make --- a/make/solaris/makefiles/sparcWorks.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/sparcWorks.make Tue Jun 17 15:27:05 2008 -0700 @@ -28,6 +28,8 @@ CC = cc CPP = CC +# Note that this 'as' is an older version of the Sun Studio 'fbe', and will +# use the older style options. The 'fbe' options will match 'cc' and 'CC'. AS = /usr/ccs/bin/as NM = /usr/ccs/bin/nm @@ -43,25 +45,33 @@ C_COMPILER_REV := \ $(shell $(CC) -V 2>&1 | grep -i "cc:" | sed -e 's/^.*\([1-9]\.[0-9][0-9]*\).*/\1/') -VALIDATED_COMPILER_REV := 5.8 -VALIDATED_C_COMPILER_REV := 5.8 +# Pick which compiler is validated +ifeq ($(JDK_MINOR_VERSION),6) + # Validated compiler for JDK6 is SS11 (5.8) + VALIDATED_COMPILER_REV := 5.8 + VALIDATED_C_COMPILER_REV := 5.8 +else + # FIXUP: Change to SS12 (5.9) once it has been validated. + # Validated compiler for JDK7 is SS12 (5.9) + #VALIDATED_COMPILER_REV := 5.9 + #VALIDATED_C_COMPILER_REV := 5.9 + VALIDATED_COMPILER_REV := 5.8 + VALIDATED_C_COMPILER_REV := 5.8 +endif +# Warning messages about not using the above validated version ENFORCE_COMPILER_REV${ENFORCE_COMPILER_REV} := ${VALIDATED_COMPILER_REV} ifneq (${COMPILER_REV},${ENFORCE_COMPILER_REV}) -dummy_target_to_enforce_compiler_rev: - @echo "Wrong ${CPP} version: ${COMPILER_REV}. " \ - "Use version ${ENFORCE_COMPILER_REV}, or set" \ - "ENFORCE_COMPILER_REV=${COMPILER_REV}." - @exit 1 +dummy_target_to_enforce_compiler_rev:=\ +$(info WARNING: You are using CC version ${COMPILER_REV} \ +and should be using version ${ENFORCE_COMPILER_REV}) endif ENFORCE_C_COMPILER_REV${ENFORCE_C_COMPILER_REV} := ${VALIDATED_C_COMPILER_REV} ifneq (${C_COMPILER_REV},${ENFORCE_C_COMPILER_REV}) -dummy_target_to_enforce_c_compiler_rev: - @echo "Wrong ${CC} version: ${C_COMPILER_REV}. " \ - "Use version ${ENFORCE_C_COMPILER_REV}, or set" \ - "ENFORCE_C_COMPILER_REV=${C_COMPILER_REV}." - @exit 1 +dummy_target_to_enforce_c_compiler_rev:=\ +$(info WARNING: You are using cc version ${C_COMPILER_REV} \ +and should be using version ${ENFORCE_C_COMPILER_REV}) endif # Fail the build if __fabsf is used. __fabsf exists only in Solaris 8 2/04 @@ -90,20 +100,44 @@ $(shell uname -r | awk -F. '{ if ($$2 >= 7) print "-DSOLARIS_7_OR_LATER"; }') CFLAGS += ${SOLARIS_7_OR_LATER} -ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) -# set ARCHFLAG/BUILDARCH which will ultimately be ARCHFLAG +# New architecture options started in SS12 (5.9), we need both styles to build. +# The older arch options for SS11 (5.8) or older and also for /usr/ccs/bin/as. +# Note: SS12 default for 32bit sparc is now the same as v8plus, so the +# settings below have changed all SS12 32bit sparc builds to be v8plus. +# The older SS11 (5.8) settings have remained as they always have been. ifeq ($(TYPE),COMPILER2) -ARCHFLAG/sparc = -xarch=v8plus + ARCHFLAG_OLD/sparc = -xarch=v8plus else -ifeq ($(TYPE),TIERED) -ARCHFLAG/sparc = -xarch=v8plus -else -ARCHFLAG/sparc = -xarch=v8 + ifeq ($(TYPE),TIERED) + ARCHFLAG_OLD/sparc = -xarch=v8plus + else + ARCHFLAG_OLD/sparc = -xarch=v8 + endif endif +ARCHFLAG_NEW/sparc = -m32 -xarch=sparc +ARCHFLAG_OLD/sparcv9 = -xarch=v9 +ARCHFLAG_NEW/sparcv9 = -m64 -xarch=sparc +ARCHFLAG_OLD/i486 = +ARCHFLAG_NEW/i486 = -m32 +ARCHFLAG_OLD/amd64 = -xarch=amd64 +ARCHFLAG_NEW/amd64 = -m64 + +# Select the ARCHFLAGs and other SS12 (5.9) options +ifeq ($(shell expr $(COMPILER_REV) \>= 5.9), 1) + ARCHFLAG/sparc = $(ARCHFLAG_NEW/sparc) + ARCHFLAG/sparcv9 = $(ARCHFLAG_NEW/sparcv9) + ARCHFLAG/i486 = $(ARCHFLAG_NEW/i486) + ARCHFLAG/amd64 = $(ARCHFLAG_NEW/amd64) +else + ARCHFLAG/sparc = $(ARCHFLAG_OLD/sparc) + ARCHFLAG/sparcv9 = $(ARCHFLAG_OLD/sparcv9) + ARCHFLAG/i486 = $(ARCHFLAG_OLD/i486) + ARCHFLAG/amd64 = $(ARCHFLAG_OLD/amd64) endif -ARCHFLAG/sparcv9 = -xarch=v9 -ARCHFLAG/i486 = -ARCHFLAG/amd64 = -xarch=amd64 + +# ARCHFLAGS for the current build arch +ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) +AS_ARCHFLAG = $(ARCHFLAG_OLD/$(BUILDARCH)) # Optional sub-directory in /usr/lib where BUILDARCH libraries are kept. ISA_DIR=$(ISA_DIR/$(BUILDARCH)) @@ -166,13 +200,13 @@ ifeq ("${Platform_arch_model}", "x86_64") -ASFLAGS += -xarch=amd64 -CFLAGS += -xarch=amd64 +ASFLAGS += $(AS_ARCHFLAG) +CFLAGS += $(ARCHFLAG/amd64) # this one seemed useless -LFLAGS_VM += -xarch=amd64 +LFLAGS_VM += $(ARCHFLAG/amd64) # this one worked -LFLAGS += -xarch=amd64 -AOUT_FLAGS += -xarch=amd64 +LFLAGS += $(ARCHFLAG/amd64) +AOUT_FLAGS += $(ARCHFLAG/amd64) # -xO3 is faster than -xO4 on specjbb with SS10 compiler OPT_CFLAGS=-xO4 $(EXTRA_OPT_CFLAGS) @@ -224,7 +258,7 @@ LFLAGS += -mt -endif # COMPILER_REV >= VALIDATED_COMPILER_REV +endif # COMPILER_REV >= 5.5 ###################################### # End 5.5 Forte compiler options # @@ -293,7 +327,7 @@ LFLAGS += -library=Crun LIBS += -library=Crun -lCrun -endif # COMPILER_REV >= VALIDATED_COMPILER_REV +endif # COMPILER_REV == 5.2 ################################## # End 5.2 Forte compiler options # @@ -320,6 +354,7 @@ # Had to hoist this higher apparently because of other changes. Must # come before -xarch specification. +# NOTE: native says optimize for the machine doing the compile, bad news. CFLAGS += -xtarget=native CFLAGS += $(ARCHFLAG) @@ -359,7 +394,7 @@ endif # 32bit x86 # The following options run into misaligned ldd problem (raj) -#OPT_CFLAGS = -fast -O4 -xarch=v8 -xchip=ultra +#OPT_CFLAGS = -fast -O4 $(ARCHFLAG/sparc) -xchip=ultra # no more exceptions CFLAGS/NOEX=-noex @@ -427,6 +462,15 @@ FASTDEBUG_CFLAGS = -g0 # The -g0 setting allows the C++ frontend to inline, which is a big win. +# Special global options for SS12 +ifeq ($(COMPILER_REV),5.9) + # There appears to be multiple issues with the new Dwarf2 debug format, so + # we tell the compiler to use the older 'stabs' debug format all the time. + # Note that this needs to be used in optimized compiles too to be 100%. + # This is a workaround for SS12 (5.9) bug 6694600 + CFLAGS += -xdebugformat=stabs +endif + # Enable the following CFLAGS additions if you need to compare the # built ELF objects. # diff -r abe7181cbe8a -r 4f91c08b3e44 make/solaris/makefiles/sparcv9.make --- a/make/solaris/makefiles/sparcv9.make Tue Jun 10 10:22:49 2008 -0700 +++ b/make/solaris/makefiles/sparcv9.make Tue Jun 17 15:27:05 2008 -0700 @@ -23,7 +23,7 @@ # Obj_Files += solaris_sparc.o -ASFLAGS += $(ARCHFLAG) +ASFLAGS += $(AS_ARCHFLAG) ifeq ("${Platform_compiler}", "sparcWorks") ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1) diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/assembler_sparc.cpp --- a/src/cpu/sparc/vm/assembler_sparc.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1523,6 +1523,21 @@ return Address(d, address(obj), oop_Relocation::spec(oop_index)); } +void MacroAssembler::set_narrow_oop(jobject obj, Register d) { + assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + + assert_not_delayed(); + // Relocation with special format (see relocInfo_sparc.hpp). + relocate(rspec, 1); + // Assembler::sethi(0x3fffff, d); + emit_long( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) ); + // Don't add relocation for 'add'. Do patching during 'sethi' processing. + add(d, 0x3ff, d); + +} + void MacroAssembler::align(int modulus) { while (offset() % modulus != 0) nop(); @@ -3406,13 +3421,15 @@ set((intptr_t)markOopDesc::prototype()->copy_set_hash(0x2), t2); st_ptr(t2, top, oopDesc::mark_offset_in_bytes()); // set up the mark word // set klass to intArrayKlass - set((intptr_t)Universe::intArrayKlassObj_addr(), t2); - ld_ptr(t2, 0, t2); - store_klass(t2, top); sub(t1, typeArrayOopDesc::header_size(T_INT), t1); add(t1, ThreadLocalAllocBuffer::alignment_reserve(), t1); sll_ptr(t1, log2_intptr(HeapWordSize/sizeof(jint)), t1); st(t1, top, arrayOopDesc::length_offset_in_bytes()); + set((intptr_t)Universe::intArrayKlassObj_addr(), t2); + ld_ptr(t2, 0, t2); + // store klass last. concurrent gcs assumes klass length is valid if + // klass field is not null. + store_klass(t2, top); verify_oop(top); // refill the tlab with an eden allocation @@ -3537,28 +3554,32 @@ } } -void MacroAssembler::load_klass(Register s, Register d) { +void MacroAssembler::load_klass(Register src_oop, Register klass) { // The number of bytes in this code is used by // MachCallDynamicJavaNode::ret_addr_offset() // if this changes, change that. if (UseCompressedOops) { - lduw(s, oopDesc::klass_offset_in_bytes(), d); - decode_heap_oop_not_null(d); + lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass); + decode_heap_oop_not_null(klass); } else { - ld_ptr(s, oopDesc::klass_offset_in_bytes(), d); + ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass); } } -// ??? figure out src vs. dst! -void MacroAssembler::store_klass(Register d, Register s1) { +void MacroAssembler::store_klass(Register klass, Register dst_oop) { if (UseCompressedOops) { - assert(s1 != d, "not enough registers"); - encode_heap_oop_not_null(d); - // Zero out entire klass field first. - st_ptr(G0, s1, oopDesc::klass_offset_in_bytes()); - st(d, s1, oopDesc::klass_offset_in_bytes()); + assert(dst_oop != klass, "not enough registers"); + encode_heap_oop_not_null(klass); + st(klass, dst_oop, oopDesc::klass_offset_in_bytes()); } else { - st_ptr(d, s1, oopDesc::klass_offset_in_bytes()); + st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes()); + } +} + +void MacroAssembler::store_klass_gap(Register s, Register d) { + if (UseCompressedOops) { + assert(s != d, "not enough registers"); + st(s, d, oopDesc::klass_gap_offset_in_bytes()); } } @@ -3622,6 +3643,7 @@ void MacroAssembler::encode_heap_oop(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + verify_oop(src); Label done; if (src == dst) { // optimize for frequent case src == dst @@ -3643,12 +3665,14 @@ void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "must be compressed"); + verify_oop(r); sub(r, G6_heapbase, r); srlx(r, LogMinObjAlignmentInBytes, r); } void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + verify_oop(src); sub(src, G6_heapbase, dst); srlx(dst, LogMinObjAlignmentInBytes, dst); } @@ -3661,11 +3685,13 @@ bpr(rc_nz, true, Assembler::pt, dst, done); delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken bind(done); + verify_oop(dst); } void MacroAssembler::decode_heap_oop_not_null(Register r) { // Do not add assert code to this unless you change vtableStubs_sparc.cpp // pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); sllx(r, LogMinObjAlignmentInBytes, r); add(r, G6_heapbase, r); @@ -3674,6 +3700,7 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { // Do not add assert code to this unless you change vtableStubs_sparc.cpp // pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); sllx(src, LogMinObjAlignmentInBytes, dst); add(dst, G6_heapbase, dst); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -1977,8 +1977,9 @@ inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } // klass oop manipulations if compressed - void load_klass(Register src_oop, Register dst); - void store_klass(Register dst_oop, Register s1); + void load_klass(Register src_oop, Register klass); + void store_klass(Register klass, Register dst_oop); + void store_klass_gap(Register s, Register dst_oop); // oop manipulations void load_heap_oop(const Address& s, Register d, int offset = 0); @@ -2103,6 +2104,8 @@ inline void set_oop_constant( jobject obj, Register d ); // uses constant_oop_address inline void set_oop ( Address obj_addr ); // same as load_address + void set_narrow_oop( jobject obj, Register d ); + // nop padding void align(int modulus); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/relocInfo_sparc.cpp --- a/src/cpu/sparc/vm/relocInfo_sparc.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -87,6 +87,17 @@ #ifdef _LP64 jint inst2; guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi"); + if (format() != 0) { + assert(type() == relocInfo::oop_type, "only narrow oops case"); + jint np = oopDesc::encode_heap_oop((oop)x); + inst &= ~Assembler::hi22(-1); + inst |= Assembler::hi22((intptr_t)np); + ip->set_long_at(0, inst); + inst2 = ip->long_at( NativeInstruction::nop_instruction_size ); + guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op"); + ip->set_long_at(NativeInstruction::nop_instruction_size, ip->set_data32_simm13( inst2, (intptr_t)np)); + break; + } ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); #ifdef COMPILER2 // [RGV] Someone must have missed putting in a reloc entry for the diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/relocInfo_sparc.hpp --- a/src/cpu/sparc/vm/relocInfo_sparc.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/relocInfo_sparc.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -31,7 +31,12 @@ // There is no need for format bits; the instructions are // sufficiently self-identifying. +#ifndef _LP64 format_width = 0 +#else + // Except narrow oops in 64-bits VM. + format_width = 1 +#endif }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -2556,7 +2556,6 @@ int total_strings = 0; int first_arg_to_pass = 0; int total_c_args = 0; - int box_offset = java_lang_boxing_object::value_offset_in_bytes(); // Skip the receiver as dtrace doesn't want to see it if( !method->is_static() ) { @@ -2721,7 +2720,8 @@ #endif /* ASSERT */ VMRegPair zero; - zero.set2(G0->as_VMReg()); + const Register g0 = G0; // without this we get a compiler warning (why??) + zero.set2(g0->as_VMReg()); int c_arg, j_arg; @@ -2778,7 +2778,9 @@ __ br_null(in_reg, true, Assembler::pn, skipUnbox); __ delayed()->mov(G0, tmp); - switch (out_sig_bt[c_arg]) { + BasicType bt = out_sig_bt[c_arg]; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt); + switch (bt) { case T_BYTE: __ ldub(in_reg, box_offset, tmp); break; case T_SHORT: diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/sparc.ad Tue Jun 17 15:27:05 2008 -0700 @@ -5471,7 +5471,6 @@ // Load Klass Pointer instruct loadKlass(iRegP dst, memory mem) %{ match(Set dst (LoadKlass mem)); - predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow()); ins_cost(MEMORY_REF_COST); size(4); @@ -5486,11 +5485,11 @@ ins_pipe(iload_mem); %} -// Load Klass Pointer -instruct loadKlassComp(iRegP dst, memory mem) %{ - match(Set dst (LoadKlass mem)); - predicate(n->in(MemNode::Address)->bottom_type()->is_narrow()); +// Load narrow Klass Pointer +instruct loadNKlass(iRegN dst, memory mem) %{ + match(Set dst (LoadNKlass mem)); ins_cost(MEMORY_REF_COST); + size(4); format %{ "LDUW $mem,$dst\t! compressed klass ptr" %} @@ -5503,9 +5502,6 @@ } else { __ lduw(base, $mem$$disp, dst); } - // klass oop never null but this is generated for nonheader klass loads - // too which can be null. - __ decode_heap_oop(dst); %} ins_pipe(iload_mem); %} @@ -5609,22 +5605,24 @@ ins_pipe(loadConP_poll); %} +instruct loadConN0(iRegN dst, immN0 src) %{ + match(Set dst src); + + size(4); + format %{ "CLR $dst\t! compressed NULL ptr" %} + ins_encode( SetNull( dst ) ); + ins_pipe(ialu_imm); +%} + instruct loadConN(iRegN dst, immN src) %{ match(Set dst src); - ins_cost(DEFAULT_COST * 2); - format %{ "SET $src,$dst\t!ptr" %} + ins_cost(DEFAULT_COST * 3/2); + format %{ "SET $src,$dst\t! compressed ptr" %} ins_encode %{ - address con = (address)$src$$constant; Register dst = $dst$$Register; - if (con == NULL) { - __ mov(G0, dst); - } else { - __ set_oop((jobject)$src$$constant, dst); - __ encode_heap_oop(dst); - } - %} - ins_pipe(loadConP); - + __ set_narrow_oop((jobject)$src$$constant, dst); + %} + ins_pipe(ialu_hi_lo_reg); %} instruct loadConL(iRegL dst, immL src, o7RegL tmp) %{ @@ -5977,7 +5975,8 @@ %} instruct decodeHeapOop(iRegP dst, iRegN src) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull); + predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant); match(Set dst (DecodeN src)); format %{ "decode_heap_oop $src, $dst" %} ins_encode %{ @@ -5987,7 +5986,8 @@ %} instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull); + predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant); match(Set dst (DecodeN src)); format %{ "decode_heap_oop_not_null $src, $dst" %} ins_encode %{ @@ -6258,6 +6258,34 @@ ins_pipe(ialu_imm); %} +// Conditional move for RegN. Only cmov(reg,reg). +instruct cmovNP_reg(cmpOpP cmp, flagsRegP pcc, iRegN dst, iRegN src) %{ + match(Set dst (CMoveN (Binary cmp pcc) (Binary dst src))); + ins_cost(150); + format %{ "MOV$cmp $pcc,$src,$dst" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) ); + ins_pipe(ialu_reg); +%} + +// This instruction also works with CmpN so we don't need cmovNN_reg. +instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary dst src))); + ins_cost(150); + size(4); + format %{ "MOV$cmp $icc,$src,$dst" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(ialu_reg); +%} + +instruct cmovNF_reg(cmpOpF cmp, flagsRegF fcc, iRegN dst, iRegN src) %{ + match(Set dst (CMoveN (Binary cmp fcc) (Binary dst src))); + ins_cost(150); + size(4); + format %{ "MOV$cmp $fcc,$src,$dst" %} + ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) ); + ins_pipe(ialu_reg); +%} + // Conditional move instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src))); @@ -6275,6 +6303,7 @@ ins_pipe(ialu_imm); %} +// This instruction also works with CmpN so we don't need cmovPN_reg. instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); ins_cost(150); @@ -6650,10 +6679,9 @@ ins_pipe( long_memory_op ); %} -instruct compareAndSwapN_bool_comp(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI res, o7RegI tmp, flagsReg ccr ) %{ +instruct compareAndSwapN_bool(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp); - + effect( USE mem_ptr, KILL ccr, KILL tmp1); format %{ "MOV $newval,O7\n\t" "CASA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t" @@ -6661,18 +6689,8 @@ "MOV 1,$res\n\t" "MOVne icc,R_G0,$res" %} - ins_encode %{ - Register Rmem = reg_to_register_object($mem_ptr$$reg); - Register Rold = reg_to_register_object($oldval$$reg); - Register Rnew = reg_to_register_object($newval$$reg); - Register Rres = reg_to_register_object($res$$reg); - - __ cas(Rmem, Rold, Rnew); - __ cmp( Rold, Rnew ); - __ mov(1, Rres); - __ movcc( Assembler::notEqual, false, Assembler::icc, G0, Rres ); - %} - + ins_encode( enc_casi(mem_ptr, oldval, newval), + enc_iflags_ne_to_boolean(res) ); ins_pipe( long_memory_op ); %} @@ -8265,6 +8283,27 @@ ins_pipe(ialu_cconly_reg_imm); %} +// Compare Narrow oops +instruct compN_iRegN(flagsReg icc, iRegN op1, iRegN op2 ) %{ + match(Set icc (CmpN op1 op2)); + + size(4); + format %{ "CMP $op1,$op2\t! compressed ptr" %} + opcode(Assembler::subcc_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); + ins_pipe(ialu_cconly_reg_reg); +%} + +instruct compN_iRegN_immN0(flagsReg icc, iRegN op1, immN0 op2 ) %{ + match(Set icc (CmpN op1 op2)); + + size(4); + format %{ "CMP $op1,$op2\t! compressed ptr" %} + opcode(Assembler::subcc_op3, Assembler::arith_op); + ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); + ins_pipe(ialu_cconly_reg_imm); +%} + //----------Max and Min-------------------------------------------------------- // Min Instructions // Conditional move for min @@ -8595,6 +8634,14 @@ ins_pipe(ialu_imm); %} +instruct cmovNL_reg(cmpOp cmp, flagsRegL xcc, iRegN dst, iRegN src) %{ + match(Set dst (CMoveN (Binary cmp xcc) (Binary dst src))); + ins_cost(150); + format %{ "MOV$cmp $xcc,$src,$dst" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) ); + ins_pipe(ialu_reg); +%} + instruct cmovPL_reg(cmpOp cmp, flagsRegL xcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); ins_cost(150); @@ -8826,16 +8873,6 @@ %} -instruct compP_iRegN_immN0(flagsRegP pcc, iRegN op1, immN0 op2 ) %{ - match(Set pcc (CmpN op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! ptr" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm); -%} - // ============================================================================ // inlined locking and unlocking diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -3222,7 +3222,8 @@ __ set((intptr_t)markOopDesc::prototype(), G4_scratch); } __ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark - __ store_klass(RinstanceKlass, RallocatedObject); // klass + __ store_klass_gap(G0, RallocatedObject); // klass gap if compressed + __ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms) { SkipIfEqual skip_if( diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/assembler_x86_32.hpp --- a/src/cpu/x86/vm/assembler_x86_32.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/assembler_x86_32.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -1054,7 +1054,7 @@ // range (0 <= offset <= page_size). void null_check(Register reg, int offset = -1); - static bool needs_explicit_null_check(int offset); + static bool needs_explicit_null_check(intptr_t offset); // Required platform-specific helpers for Label::patch_instructions. // They _shadow_ the declarations in AbstractAssembler, which are undefined. diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/assembler_x86_64.cpp --- a/src/cpu/x86/vm/assembler_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/assembler_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -683,7 +683,8 @@ case REP8(0xB8): // movl/q r, #32/#64(oop?) if (which == end_pc_operand) return ip + (is_64bit ? 8 : 4); - assert((which == call32_operand || which == imm64_operand) && is_64bit, ""); + assert((which == call32_operand || which == imm64_operand) && is_64bit || + which == narrow_oop_operand && !is_64bit, ""); return ip; case 0x69: // imul r, a, #32 @@ -909,7 +910,8 @@ } else if (r->is_call() || format == call32_operand) { opnd = locate_operand(inst, call32_operand); } else if (r->is_data()) { - assert(format == imm64_operand || format == disp32_operand, "format ok"); + assert(format == imm64_operand || format == disp32_operand || + format == narrow_oop_operand, "format ok"); opnd = locate_operand(inst, (WhichOperand) format); } else { assert(format == 0, "cannot specify a format"); @@ -4933,6 +4935,8 @@ movq(Address(top, arrayOopDesc::length_offset_in_bytes()), t1); // set klass to intArrayKlass movptr(t1, ExternalAddress((address) Universe::intArrayKlassObj_addr())); + // store klass last. concurrent gcs assumes klass length is valid if + // klass field is not null. store_klass(top, t1); // refill the tlab with an eden allocation @@ -5003,8 +5007,7 @@ jcc(Assembler::notEqual, cas_label); // The bias pattern is present in the object's header. Need to check // whether the bias owner and the epoch are both still current. - load_klass(tmp_reg, obj_reg); - movq(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + load_prototype_header(tmp_reg, obj_reg); orq(tmp_reg, r15_thread); xorq(tmp_reg, swap_reg); andq(tmp_reg, ~((int) markOopDesc::age_mask_in_place)); @@ -5078,8 +5081,7 @@ // // FIXME: due to a lack of registers we currently blow away the age // bits in this situation. Should attempt to preserve them. - load_klass(tmp_reg, obj_reg); - movq(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + load_prototype_header(tmp_reg, obj_reg); orq(tmp_reg, r15_thread); if (os::is_MP()) { lock(); @@ -5109,8 +5111,7 @@ // // FIXME: due to a lack of registers we currently blow away the age // bits in this situation. Should attempt to preserve them. - load_klass(tmp_reg, obj_reg); - movq(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + load_prototype_header(tmp_reg, obj_reg); if (os::is_MP()) { lock(); } @@ -5154,17 +5155,32 @@ } } +void MacroAssembler::load_prototype_header(Register dst, Register src) { + if (UseCompressedOops) { + movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); + movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } else { + movq(dst, Address(src, oopDesc::klass_offset_in_bytes())); + movq(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } +} + void MacroAssembler::store_klass(Register dst, Register src) { if (UseCompressedOops) { encode_heap_oop_not_null(src); - // zero the entire klass field first as the gap needs to be zeroed too. - movptr(Address(dst, oopDesc::klass_offset_in_bytes()), NULL_WORD); movl(Address(dst, oopDesc::klass_offset_in_bytes()), src); } else { movq(Address(dst, oopDesc::klass_offset_in_bytes()), src); } } +void MacroAssembler::store_klass_gap(Register dst, Register src) { + if (UseCompressedOops) { + // Store to klass gap in destination + movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src); + } +} + void MacroAssembler::load_heap_oop(Register dst, Address src) { if (UseCompressedOops) { movl(dst, src); @@ -5188,13 +5204,15 @@ void MacroAssembler::encode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); #ifdef ASSERT - Label ok; - pushq(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); - jcc(Assembler::equal, ok); - stop("MacroAssembler::encode_heap_oop: heap base corrupted?"); - bind(ok); - popq(rscratch1); + if (CheckCompressedOops) { + Label ok; + pushq(rscratch1); // cmpptr trashes rscratch1 + cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); + jcc(Assembler::equal, ok); + stop("MacroAssembler::encode_heap_oop: heap base corrupted?"); + bind(ok); + popq(rscratch1); + } #endif verify_oop(r, "broken oop in encode_heap_oop"); testq(r, r); @@ -5206,11 +5224,13 @@ void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "should be compressed"); #ifdef ASSERT - Label ok; - testq(r, r); - jcc(Assembler::notEqual, ok); - stop("null oop passed to encode_heap_oop_not_null"); - bind(ok); + if (CheckCompressedOops) { + Label ok; + testq(r, r); + jcc(Assembler::notEqual, ok); + stop("null oop passed to encode_heap_oop_not_null"); + bind(ok); + } #endif verify_oop(r, "broken oop in encode_heap_oop_not_null"); subq(r, r12_heapbase); @@ -5220,11 +5240,13 @@ void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { assert (UseCompressedOops, "should be compressed"); #ifdef ASSERT - Label ok; - testq(src, src); - jcc(Assembler::notEqual, ok); - stop("null oop passed to encode_heap_oop_not_null2"); - bind(ok); + if (CheckCompressedOops) { + Label ok; + testq(src, src); + jcc(Assembler::notEqual, ok); + stop("null oop passed to encode_heap_oop_not_null2"); + bind(ok); + } #endif verify_oop(src, "broken oop in encode_heap_oop_not_null2"); if (dst != src) { @@ -5237,14 +5259,16 @@ void MacroAssembler::decode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); #ifdef ASSERT - Label ok; - pushq(rscratch1); - cmpptr(r12_heapbase, - ExternalAddress((address)Universe::heap_base_addr())); - jcc(Assembler::equal, ok); - stop("MacroAssembler::decode_heap_oop: heap base corrupted?"); - bind(ok); - popq(rscratch1); + if (CheckCompressedOops) { + Label ok; + pushq(rscratch1); + cmpptr(r12_heapbase, + ExternalAddress((address)Universe::heap_base_addr())); + jcc(Assembler::equal, ok); + stop("MacroAssembler::decode_heap_oop: heap base corrupted?"); + bind(ok); + popq(rscratch1); + } #endif Label done; @@ -5265,6 +5289,7 @@ assert (UseCompressedOops, "should only be used for compressed headers"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); } @@ -5273,10 +5298,24 @@ assert (UseCompressedOops, "should only be used for compressed headers"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); } +void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { + assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + + // movl dst,obj + InstructionMark im(this); + int encode = prefix_and_encode(dst->encoding()); + emit_byte(0xB8 | encode); + emit_data(oop_index, rspec, narrow_oop_operand); +} + + Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { switch (cond) { // Note some conditions are synonyms for others diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/assembler_x86_64.hpp --- a/src/cpu/x86/vm/assembler_x86_64.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/assembler_x86_64.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -490,7 +490,12 @@ imm64_operand = 0, // embedded 64-bit immediate operand disp32_operand = 1, // embedded 32-bit displacement call32_operand = 2, // embedded 32-bit self-relative displacement +#ifndef AMD64 _WhichOperand_limit = 3 +#else + narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop + _WhichOperand_limit = 4 +#endif }; public: @@ -1023,7 +1028,7 @@ // is needed if the offset is within a certain range (0 <= offset <= // page_size). void null_check(Register reg, int offset = -1); - static bool needs_explicit_null_check(int offset); + static bool needs_explicit_null_check(intptr_t offset); // Required platform-specific helpers for Label::patch_instructions. // They _shadow_ the declarations in AbstractAssembler, which are undefined. @@ -1104,6 +1109,9 @@ // oop manipulations void load_klass(Register dst, Register src); void store_klass(Register dst, Register src); + void store_klass_gap(Register dst, Register src); + + void load_prototype_header(Register dst, Register src); void load_heap_oop(Register dst, Address src); void store_heap_oop(Address dst, Register src); @@ -1114,6 +1122,8 @@ void encode_heap_oop_not_null(Register dst, Register src); void decode_heap_oop_not_null(Register dst, Register src); + void set_narrow_oop(Register dst, jobject obj); + // Stack frame creation/removal void enter(); void leave(); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -233,7 +233,7 @@ assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); - Label not_subtype, loop; + Label not_subtype, not_subtype_pop, loop; // Profile the not-null value's klass. profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, rdi @@ -272,12 +272,13 @@ // and we store values in objArrays always encoded, thus we need to encode value // before repne if (UseCompressedOops) { + pushq(rax); encode_heap_oop(rax); repne_scanl(); // Not equal? - jcc(Assembler::notEqual, not_subtype); - // decode heap oop here for movq - decode_heap_oop(rax); + jcc(Assembler::notEqual, not_subtype_pop); + // restore heap oop here for movq + popq(rax); } else { repne_scanq(); jcc(Assembler::notEqual, not_subtype); @@ -287,9 +288,10 @@ Klass::secondary_super_cache_offset_in_bytes()), rax); jmp(ok_is_subtype); + bind(not_subtype_pop); + // restore heap oop here for miss + if (UseCompressedOops) popq(rax); bind(not_subtype); - // decode heap oop here for miss - if (UseCompressedOops) decode_heap_oop(rax); profile_typecheck_failed(rcx); // blows rcx } diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/relocInfo_x86.cpp --- a/src/cpu/x86/vm/relocInfo_x86.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -30,11 +30,15 @@ #ifdef AMD64 x += o; typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm64, call32 + WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm64, call32, narrow oop assert(which == Assembler::disp32_operand || + which == Assembler::narrow_oop_operand || which == Assembler::imm64_operand, "format unpacks ok"); if (which == Assembler::imm64_operand) { *pd_address_in_code() = x; + } else if (which == Assembler::narrow_oop_operand) { + address disp = Assembler::locate_operand(addr(), which); + *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); } else { // Note: Use runtime_call_type relocations for call32_operand. address ip = addr(); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/relocInfo_x86.hpp --- a/src/cpu/x86/vm/relocInfo_x86.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/relocInfo_x86.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -29,5 +29,10 @@ offset_unit = 1, // Encodes Assembler::disp32_operand vs. Assembler::imm32_operand. +#ifndef AMD64 format_width = 1 +#else + // vs Assembler::narrow_oop_operand. + format_width = 2 +#endif }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1920,7 +1920,6 @@ int total_strings = 0; int first_arg_to_pass = 0; int total_c_args = 0; - int box_offset = java_lang_boxing_object::value_offset_in_bytes(); if( !method->is_static() ) { // Pass in receiver first in_sig_bt[i++] = T_OBJECT; @@ -2131,7 +2130,10 @@ assert(dst.first()->is_stack() && (!dst.second()->is_valid() || dst.second()->is_stack()), "value(s) must go into stack slots"); - if ( out_sig_bt[c_arg] == T_LONG ) { + + BasicType bt = out_sig_bt[c_arg]; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt); + if ( bt == T_LONG ) { __ movl(rbx, Address(in_reg, box_offset + VMRegImpl::stack_slot_size)); __ movl(Address(rsp, reg2offset_out(dst.second())), rbx); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1950,7 +1950,6 @@ int total_strings = 0; int first_arg_to_pass = 0; int total_c_args = 0; - int box_offset = java_lang_boxing_object::value_offset_in_bytes(); // Skip the receiver as dtrace doesn't want to see it if( !method->is_static() ) { @@ -2197,8 +2196,10 @@ __ testq(in_reg, in_reg); __ jcc(Assembler::zero, skipUnbox); + BasicType bt = out_sig_bt[c_arg]; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt); Address src1(in_reg, box_offset); - if ( out_sig_bt[c_arg] == T_LONG ) { + if ( bt == T_LONG ) { __ movq(in_reg, src1); __ movq(stack_dst, in_reg); assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); @@ -2460,8 +2461,10 @@ Label skip; __ testq(r, r); __ jcc(Assembler::equal, skip); + BasicType bt = out_sig_bt[c_arg]; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt); Address src1(r, box_offset); - if ( out_sig_bt[c_arg] == T_LONG ) { + if ( bt == T_LONG ) { __ movq(r, src1); } else { __ movl(r, src1); diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -3163,7 +3163,9 @@ __ movptr(Address(rax, oopDesc::mark_offset_in_bytes()), (intptr_t) markOopDesc::prototype()); // header (address 0x1) } - __ store_klass(rax, rsi); // klass + __ xorl(rcx, rcx); // use zero reg to clear memory (shorter code) + __ store_klass_gap(rax, rcx); // zero klass gap for compressed oops + __ store_klass(rax, rsi); // store klass last __ jmp(done); } diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/x86_32.ad Tue Jun 17 15:27:05 2008 -0700 @@ -3806,6 +3806,78 @@ masm.bind(DONE_LABEL); %} + enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result) %{ + Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP; + MacroAssembler masm(&cbuf); + + Register ary1Reg = as_Register($ary1$$reg); + Register ary2Reg = as_Register($ary2$$reg); + Register tmp1Reg = as_Register($tmp1$$reg); + Register tmp2Reg = as_Register($tmp2$$reg); + Register resultReg = as_Register($result$$reg); + + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // Check the input args + masm.cmpl(ary1Reg, ary2Reg); + masm.jcc(Assembler::equal, TRUE_LABEL); + masm.testl(ary1Reg, ary1Reg); + masm.jcc(Assembler::zero, FALSE_LABEL); + masm.testl(ary2Reg, ary2Reg); + masm.jcc(Assembler::zero, FALSE_LABEL); + + // Check the lengths + masm.movl(tmp2Reg, Address(ary1Reg, length_offset)); + masm.movl(resultReg, Address(ary2Reg, length_offset)); + masm.cmpl(tmp2Reg, resultReg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.testl(resultReg, resultReg); + masm.jcc(Assembler::zero, TRUE_LABEL); + + // Get the number of 4 byte vectors to compare + masm.shrl(resultReg, 1); + + // Check for odd-length arrays + masm.andl(tmp2Reg, 1); + masm.testl(tmp2Reg, tmp2Reg); + masm.jcc(Assembler::zero, COMPARE_LOOP_HDR); + + // Compare 2-byte "tail" at end of arrays + masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); + masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); + masm.cmpl(tmp1Reg, tmp2Reg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.testl(resultReg, resultReg); + masm.jcc(Assembler::zero, TRUE_LABEL); + + // Setup compare loop + masm.bind(COMPARE_LOOP_HDR); + // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays + masm.leal(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); + masm.leal(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); + masm.negl(resultReg); + + // 4-byte-wide compare loop + masm.bind(COMPARE_LOOP); + masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0)); + masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0)); + masm.cmpl(ary1Reg, ary2Reg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.increment(resultReg); + masm.jcc(Assembler::notZero, COMPARE_LOOP); + + masm.bind(TRUE_LABEL); + masm.movl(resultReg, 1); // return true + masm.jmp(DONE_LABEL); + + masm.bind(FALSE_LABEL); + masm.xorl(resultReg, resultReg); // return false + + // That's it + masm.bind(DONE_LABEL); + %} + enc_class enc_pop_rdx() %{ emit_opcode(cbuf,0x5A); %} @@ -11565,6 +11637,17 @@ ins_pipe( pipe_slow ); %} +// fast array equals +instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{ + match(Set result (AryEq ary1 ary2)); + effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr); + //ins_cost(300); + + format %{ "Array Equals $ary1,$ary2 -> $result // KILL EAX, EBX" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) ); + ins_pipe( pipe_slow ); +%} + //----------Control Flow Instructions------------------------------------------ // Signed compare Instructions instruct compI_eReg(eFlagsReg cr, eRegI op1, eRegI op2) %{ diff -r abe7181cbe8a -r 4f91c08b3e44 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Tue Jun 10 10:22:49 2008 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Tue Jun 17 15:27:05 2008 -0700 @@ -3808,6 +3808,78 @@ masm.bind(DONE_LABEL); %} + enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, rbx_RegI tmp2, rcx_RegI result) %{ + Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP; + MacroAssembler masm(&cbuf); + + Register ary1Reg = as_Register($ary1$$reg); + Register ary2Reg = as_Register($ary2$$reg); + Register tmp1Reg = as_Register($tmp1$$reg); + Register tmp2Reg = as_Register($tmp2$$reg); + Register resultReg = as_Register($result$$reg); + + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // Check the input args + masm.cmpq(ary1Reg, ary2Reg); + masm.jcc(Assembler::equal, TRUE_LABEL); + masm.testq(ary1Reg, ary1Reg); + masm.jcc(Assembler::zero, FALSE_LABEL); + masm.testq(ary2Reg, ary2Reg); + masm.jcc(Assembler::zero, FALSE_LABEL); + + // Check the lengths + masm.movl(tmp2Reg, Address(ary1Reg, length_offset)); + masm.movl(resultReg, Address(ary2Reg, length_offset)); + masm.cmpl(tmp2Reg, resultReg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.testl(resultReg, resultReg); + masm.jcc(Assembler::zero, TRUE_LABEL); + + // Get the number of 4 byte vectors to compare + masm.shrl(resultReg, 1); + + // Check for odd-length arrays + masm.andl(tmp2Reg, 1); + masm.testl(tmp2Reg, tmp2Reg); + masm.jcc(Assembler::zero, COMPARE_LOOP_HDR); + + // Compare 2-byte "tail" at end of arrays + masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); + masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); + masm.cmpl(tmp1Reg, tmp2Reg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.testl(resultReg, resultReg); + masm.jcc(Assembler::zero, TRUE_LABEL); + + // Setup compare loop + masm.bind(COMPARE_LOOP_HDR); + // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays + masm.leaq(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); + masm.leaq(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); + masm.negq(resultReg); + + // 4-byte-wide compare loop + masm.bind(COMPARE_LOOP); + masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0)); + masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0)); + masm.cmpl(ary1Reg, ary2Reg); + masm.jcc(Assembler::notEqual, FALSE_LABEL); + masm.incrementq(resultReg); + masm.jcc(Assembler::notZero, COMPARE_LOOP); + + masm.bind(TRUE_LABEL); + masm.movl(resultReg, 1); // return true + masm.jmp(DONE_LABEL); + + masm.bind(FALSE_LABEL); + masm.xorl(resultReg, resultReg); // return false + + // That's it + masm.bind(DONE_LABEL); + %} + enc_class enc_rethrow() %{ cbuf.set_inst_mark(); @@ -5202,15 +5274,15 @@ %} %} -// Indirect Memory Times Scale Plus Index Register Plus Offset Operand -operand indIndexScaleOffsetComp(rRegN src, immL32 off, r12RegL base) %{ +// Indirect Narrow Oop Plus Offset Operand +operand indNarrowOopOffset(rRegN src, immL32 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN src base) off); + match(AddP (DecodeN src) off); op_cost(10); - format %{"[$base + $src << 3 + $off] (compressed)" %} + format %{"[R12 + $src << 3 + $off] (compressed oop addressing)" %} interface(MEMORY_INTER) %{ - base($base); + base(0xc); // R12 index($src); scale(0x3); disp($off); @@ -5365,7 +5437,7 @@ opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset, - indIndexScaleOffsetComp); + indNarrowOopOffset); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -6044,10 +6116,9 @@ %} // Load Compressed Pointer -instruct loadN(rRegN dst, memory mem, rFlagsReg cr) +instruct loadN(rRegN dst, memory mem) %{ match(Set dst (LoadN mem)); - effect(KILL cr); ins_cost(125); // XXX format %{ "movl $dst, $mem\t# compressed ptr" %} @@ -6064,7 +6135,6 @@ instruct loadKlass(rRegP dst, memory mem) %{ match(Set dst (LoadKlass mem)); - predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow()); ins_cost(125); // XXX format %{ "movq $dst, $mem\t# class" %} @@ -6073,22 +6143,17 @@ ins_pipe(ialu_reg_mem); // XXX %} -// Load Klass Pointer -instruct loadKlassComp(rRegP dst, memory mem) -%{ - match(Set dst (LoadKlass mem)); - predicate(n->in(MemNode::Address)->bottom_type()->is_narrow()); +// Load narrow Klass Pointer +instruct loadNKlass(rRegN dst, memory mem) +%{ + match(Set dst (LoadNKlass mem)); ins_cost(125); // XXX - format %{ "movl $dst, $mem\t# compressed class\n\t" - "decode_heap_oop $dst,$dst" %} + format %{ "movl $dst, $mem\t# compressed klass ptr" %} ins_encode %{ Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); Register dst = as_Register($dst$$reg); __ movl(dst, addr); - // klass is never null in the header but this is generated for all - // klass loads not just the _klass field in the header. - __ decode_heap_oop(dst); %} ins_pipe(ialu_reg_mem); // XXX %} @@ -6362,16 +6427,14 @@ match(Set dst src); ins_cost(125); - format %{ "movq $dst, $src\t# compressed ptr\n\t" - "encode_heap_oop_not_null $dst,$dst" %} + format %{ "movl $dst, $src\t# compressed ptr" %} ins_encode %{ address con = (address)$src$$constant; Register dst = $dst$$Register; if (con == NULL) { ShouldNotReachHere(); } else { - __ movoop(dst, (jobject)$src$$constant); - __ encode_heap_oop_not_null(dst); + __ set_narrow_oop(dst, (jobject)$src$$constant); } %} ins_pipe(ialu_reg_fat); // XXX @@ -6633,13 +6696,12 @@ %} // Store Compressed Pointer -instruct storeN(memory mem, rRegN src, rFlagsReg cr) +instruct storeN(memory mem, rRegN src) %{ match(Set mem (StoreN mem src)); - effect(KILL cr); ins_cost(125); // XXX - format %{ "movl $mem, $src\t# ptr" %} + format %{ "movl $mem, $src\t# compressed ptr" %} ins_encode %{ Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); Register src = as_Register($src$$reg); @@ -7027,7 +7089,8 @@ %} instruct decodeHeapOop(rRegP dst, rRegN src, rFlagsReg cr) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull); + predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant); match(Set dst (DecodeN src)); effect(KILL cr); format %{ "decode_heap_oop $dst,$src" %} @@ -7043,7 +7106,8 @@ %} instruct decodeHeapOop_not_null(rRegP dst, rRegN src) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull); + predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant); match(Set dst (DecodeN src)); format %{ "decode_heap_oop_not_null $dst,$src" %} ins_encode %{ @@ -7143,6 +7207,30 @@ %} // Conditional move +instruct cmovN_reg(rRegN dst, rRegN src, rFlagsReg cr, cmpOp cop) +%{ + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# signed, compressed ptr" %} + opcode(0x0F, 0x40); + ins_encode(REX_reg_reg(dst, src), enc_cmov(cop), reg_reg(dst, src)); + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move +instruct cmovN_regU(rRegN dst, rRegN src, rFlagsRegU cr, cmpOpU cop) +%{ + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# unsigned, compressed ptr" %} + opcode(0x0F, 0x40); + ins_encode(REX_reg_reg(dst, src), enc_cmov(cop), reg_reg(dst, src)); + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop) %{ match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); @@ -10862,6 +10950,18 @@ ins_pipe( pipe_slow ); %} +// fast array equals +instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, + rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr) %{ + match(Set result (AryEq ary1 ary2)); + effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr); + //ins_cost(300); + + format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) ); + ins_pipe( pipe_slow ); +%} + //----------Control Flow Instructions------------------------------------------ // Signed compare Instructions @@ -11055,14 +11155,50 @@ ins_pipe(ialu_cr_reg_imm); %} + +instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) +%{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed ptr" %} + ins_encode %{ __ cmpl(as_Register($op1$$reg), as_Register($op2$$reg)); %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) +%{ + match(Set cr (CmpN src (LoadN mem))); + + ins_cost(500); // XXX + format %{ "cmpl $src, mem\t# compressed ptr" %} + ins_encode %{ + Address adr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); + __ cmpl(as_Register($src$$reg), adr); + %} + ins_pipe(ialu_cr_reg_mem); +%} + instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ match(Set cr (CmpN src zero)); - format %{ "testl $src, $src" %} + format %{ "testl $src, $src\t# compressed ptr" %} ins_encode %{ __ testl($src$$Register, $src$$Register); %} ins_pipe(ialu_cr_reg_imm); %} +instruct testN_reg_mem(rFlagsReg cr, memory mem, immN0 zero) +%{ + match(Set cr (CmpN (LoadN mem) zero)); + + ins_cost(500); // XXX + format %{ "testl $mem, 0xffffffff\t# compressed ptr" %} + ins_encode %{ + Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); + __ cmpl(addr, (int)0xFFFFFFFF); + %} + ins_pipe(ialu_cr_reg_mem); +%} + // Yanked all unsigned pointer compare operations. // Pointer compares are done with CmpP which is already unsigned. diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp --- a/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -40,7 +40,7 @@ movptr(thread, tls); } -bool MacroAssembler::needs_explicit_null_check(int offset) { +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Linux kernel guarantees that the first page is always unmapped. Don't // assume anything more than that. bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp --- a/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -66,8 +66,21 @@ } } -// NOTE: since the linux kernel resides at the low end of -// user address space, no null pointer check is needed. -bool MacroAssembler::needs_explicit_null_check(int offset) { - return offset < 0 || offset >= 0x100000; +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { + // Exception handler checks the nmethod's implicit null checks table + // only when this method returns false. + if (UseCompressedOops) { + // The first page after heap_base is unmapped and + // the 'offset' is equal to [heap_base + offset] for + // narrow oop implicit null checks. + uintptr_t heap_base = (uintptr_t)Universe::heap_base(); + if ((uintptr_t)offset >= heap_base) { + // Normalize offset for the next check. + offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + } + } + // Linux kernel guarantees that the first page is always unmapped. Don't + // assume anything more than that. + bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); + return !offset_in_first_page; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp --- a/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -80,7 +80,7 @@ popl(thread); } -bool MacroAssembler::needs_explicit_null_check(int offset) { +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Identical to Sparc/Solaris code bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); return !offset_in_first_page; diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp --- a/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -86,8 +86,21 @@ } } -bool MacroAssembler::needs_explicit_null_check(int offset) { +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Identical to Sparc/Solaris code + + // Exception handler checks the nmethod's implicit null checks table + // only when this method returns false. + if (UseCompressedOops) { + // The first page after heap_base is unmapped and + // the 'offset' is equal to [heap_base + offset] for + // narrow oop implicit null checks. + uintptr_t heap_base = (uintptr_t)Universe::heap_base(); + if ((uintptr_t)offset >= heap_base) { + // Normalize offset for the next check. + offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + } + } bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); return !offset_in_first_page; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp --- a/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -59,6 +59,6 @@ movl(thread, Address(thread, ThreadLocalStorage::get_thread_ptr_offset())); } -bool MacroAssembler::needs_explicit_null_check(int offset) { +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { return offset < 0 || (int)os::vm_page_size() <= offset; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp --- a/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -66,6 +66,18 @@ } } -bool MacroAssembler::needs_explicit_null_check(int offset) { - return offset < 0 || (int)os::vm_page_size() <= offset; +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { + // Exception handler checks the nmethod's implicit null checks table + // only when this method returns false. + if (UseCompressedOops) { + // The first page after heap_base is unmapped and + // the 'offset' is equal to [heap_base + offset] for + // narrow oop implicit null checks. + uintptr_t heap_base = (uintptr_t)Universe::heap_base(); + if ((uintptr_t)offset >= heap_base) { + // Normalize offset for the next check. + offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + } + } + return offset < 0 || os::vm_page_size() <= offset; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/adlc/forms.cpp --- a/src/share/vm/adlc/forms.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/adlc/forms.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -252,6 +252,7 @@ if( strcmp(opType,"LoadF")==0 ) return Form::idealF; if( strcmp(opType,"LoadI")==0 ) return Form::idealI; if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP; + if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealN; if( strcmp(opType,"LoadL")==0 ) return Form::idealL; if( strcmp(opType,"LoadL_unaligned")==0 ) return Form::idealL; if( strcmp(opType,"LoadPLocked")==0 ) return Form::idealP; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/adlc/formssel.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -3313,7 +3313,7 @@ "Store8B","Store4B","Store8C","Store4C","Store2C", "Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" , "Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S", - "LoadRange", "LoadKlass", "LoadL_unaligned", "LoadD_unaligned", + "LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned", "LoadPLocked", "LoadLLocked", "StorePConditional", "StoreLConditional", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN", diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -218,6 +218,13 @@ ciInstanceKlass* callee_holder = ciEnv::get_instance_klass_for_declared_method_holder(holder); ciInstanceKlass* actual_recv = callee_holder; + // some methods are obviously bindable without any type checks so + // convert them directly to an invokespecial. + if (target->is_loaded() && !target->is_abstract() && + target->can_be_statically_bound() && code == Bytecodes::_invokevirtual) { + code = Bytecodes::_invokespecial; + } + // compute size of arguments int arg_size = target->arg_size(); if (!target->is_loaded() && code == Bytecodes::_invokestatic) { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -392,12 +392,12 @@ assert(!is_java_lang_Object(), "bootstrap OK"); // Size in bytes of my fields, including inherited fields. - int fsize = nonstatic_field_size() * wordSize; + int fsize = nonstatic_field_size() * heapOopSize; ciInstanceKlass* super = this->super(); GrowableArray* super_fields = NULL; if (super != NULL && super->has_nonstatic_fields()) { - int super_fsize = super->nonstatic_field_size() * wordSize; + int super_fsize = super->nonstatic_field_size() * heapOopSize; int super_flen = super->nof_nonstatic_fields(); super_fields = super->_nonstatic_fields; assert(super_flen == 0 || super_fields != NULL, "first get nof_fields"); @@ -438,7 +438,7 @@ // This is a minor inefficiency classFileParser.cpp. last_offset = offset + size; } - assert(last_offset <= (int)sizeof(oopDesc) + fsize, "no overflow"); + assert(last_offset <= (int)instanceOopDesc::base_offset_in_bytes() + fsize, "no overflow"); #endif _nonstatic_fields = fields; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/ci/ciMethod.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -878,7 +878,7 @@ (TieredCompilation && code->compiler() != NULL && code->compiler()->is_c1())) { return 0; } - return code->code_size(); + return code->code_end() - code->verified_entry_point(); ) } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -44,6 +44,7 @@ // Used for backward compatibility reasons: // - to check for javac bug fixes that happened after 1.5 +// - also used as the max version when running in jdk6 #define JAVA_6_VERSION 50 @@ -2664,8 +2665,8 @@ fac.static_byte_count ), wordSize ); static_field_size = (next_static_type_offset - next_static_oop_offset) / wordSize; - first_nonstatic_field_offset = (instanceOopDesc::header_size() + - nonstatic_field_size) * wordSize; + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; next_nonstatic_field_offset = first_nonstatic_field_offset; // Add fake fields for java.lang.Class instances (also see below) @@ -2734,9 +2735,9 @@ next_nonstatic_byte_offset = next_nonstatic_short_offset + (nonstatic_short_count * BytesPerShort); next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + - nonstatic_byte_count ), wordSize ); + nonstatic_byte_count ), heapOopSize ); orig_nonstatic_field_size = nonstatic_field_size + - ((next_nonstatic_type_offset - first_nonstatic_field_offset)/wordSize); + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); } #endif bool compact_fields = CompactFields; @@ -2791,18 +2792,8 @@ int nonstatic_short_space_offset; int nonstatic_byte_space_offset; - bool compact_into_header = (UseCompressedOops && - allocation_style == 1 && compact_fields && - !super_has_nonstatic_fields); - - if( compact_into_header || nonstatic_double_count > 0 ) { - int offset; - // Pack something in with the header if no super klass has done so. - if (compact_into_header) { - offset = oopDesc::klass_gap_offset_in_bytes(); - } else { - offset = next_nonstatic_double_offset; - } + if( nonstatic_double_count > 0 ) { + int offset = next_nonstatic_double_offset; next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); if( compact_fields && offset != next_nonstatic_double_offset ) { // Allocate available fields into the gap before double field. @@ -2830,8 +2821,7 @@ } // Allocate oop field in the gap if there are no other fields for that. nonstatic_oop_space_offset = offset; - if(!compact_into_header && length >= heapOopSize && - nonstatic_oop_count > 0 && + if( length >= heapOopSize && nonstatic_oop_count > 0 && allocation_style != 0 ) { // when oop fields not first nonstatic_oop_count -= 1; nonstatic_oop_space_count = 1; // Only one will fit @@ -2854,14 +2844,13 @@ } else { // allocation_style == 1 next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count; if( nonstatic_oop_count > 0 ) { - notaligned_offset = next_nonstatic_oop_offset; next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); } notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } - next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); + next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/wordSize); + - first_nonstatic_field_offset)/heapOopSize); // Iterate over fields again and compute correct offsets. // The field allocation type was temporarily stored in the offset slot. @@ -2962,9 +2951,10 @@ // Size of instances int instance_size; + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); instance_size = align_object_size(next_nonstatic_type_offset / wordSize); - assert(instance_size == align_object_size(instanceOopDesc::header_size() + nonstatic_field_size), "consistent layout helper value"); + assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value"); // Size of non-static oop map blocks (in words) allocated at end of klass int nonstatic_oop_map_size = compute_oop_map_size(super_klass, nonstatic_oop_map_count, first_nonstatic_oop_offset); @@ -3122,13 +3112,15 @@ #ifndef PRODUCT if( PrintCompactFieldsSavings ) { if( nonstatic_field_size < orig_nonstatic_field_size ) { - tty->print("[Saved %d of %3d words in %s]\n", - orig_nonstatic_field_size - nonstatic_field_size, - orig_nonstatic_field_size, this_klass->external_name()); + tty->print("[Saved %d of %d bytes in %s]\n", + (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + this_klass->external_name()); } else if( nonstatic_field_size > orig_nonstatic_field_size ) { - tty->print("[Wasted %d over %3d words in %s]\n", - nonstatic_field_size - orig_nonstatic_field_size, - orig_nonstatic_field_size, this_klass->external_name()); + tty->print("[Wasted %d over %d bytes in %s]\n", + (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + this_klass->external_name()); } } #endif @@ -3516,9 +3508,11 @@ } bool ClassFileParser::is_supported_version(u2 major, u2 minor) { + u2 max_version = JDK_Version::is_gte_jdk17x_version() ? + JAVA_MAX_SUPPORTED_VERSION : JAVA_6_VERSION; return (major >= JAVA_MIN_SUPPORTED_VERSION) && - (major <= JAVA_MAX_SUPPORTED_VERSION) && - ((major != JAVA_MAX_SUPPORTED_VERSION) || + (major <= max_version) && + ((major != max_version) || (minor <= JAVA_MAX_SUPPORTED_MINOR_VERSION)); } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1872,7 +1872,7 @@ box->float_field_put(value_offset, value->f); break; case T_DOUBLE: - box->double_field_put(value_offset, value->d); + box->double_field_put(long_value_offset, value->d); break; case T_BYTE: box->byte_field_put(value_offset, value->b); @@ -1884,7 +1884,7 @@ box->int_field_put(value_offset, value->i); break; case T_LONG: - box->long_field_put(value_offset, value->j); + box->long_field_put(long_value_offset, value->j); break; default: return NULL; @@ -1915,7 +1915,7 @@ value->f = box->float_field(value_offset); break; case T_DOUBLE: - value->d = box->double_field(value_offset); + value->d = box->double_field(long_value_offset); break; case T_BYTE: value->b = box->byte_field(value_offset); @@ -1927,7 +1927,7 @@ value->i = box->int_field(value_offset); break; case T_LONG: - value->j = box->long_field(value_offset); + value->j = box->long_field(long_value_offset); break; default: return T_ILLEGAL; @@ -1949,7 +1949,7 @@ box->float_field_put(value_offset, value->f); break; case T_DOUBLE: - box->double_field_put(value_offset, value->d); + box->double_field_put(long_value_offset, value->d); break; case T_BYTE: box->byte_field_put(value_offset, value->b); @@ -1961,7 +1961,7 @@ box->int_field_put(value_offset, value->i); break; case T_LONG: - box->long_field_put(value_offset, value->j); + box->long_field_put(long_value_offset, value->j); break; default: return T_ILLEGAL; @@ -2163,6 +2163,7 @@ int java_lang_reflect_Field::signature_offset; int java_lang_reflect_Field::annotations_offset; int java_lang_boxing_object::value_offset; +int java_lang_boxing_object::long_value_offset; int java_lang_ref_Reference::referent_offset; int java_lang_ref_Reference::queue_offset; int java_lang_ref_Reference::next_offset; @@ -2282,10 +2283,7 @@ // are not available to determine the offset_of_static_fields. void JavaClasses::compute_hard_coded_offsets() { const int x = heapOopSize; - // Objects don't get allocated in the gap in the header with compressed oops - // for these special classes because hard coded offsets can't be conditional - // so base_offset_in_bytes() is wrong here, allocate after the header. - const int header = sizeof(instanceOopDesc); + const int header = instanceOopDesc::base_offset_in_bytes(); // Do the String Class java_lang_String::value_offset = java_lang_String::hc_value_offset * x + header; @@ -2308,7 +2306,8 @@ java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header; // java_lang_boxing_object - java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset * x + header; + java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset + header; + java_lang_boxing_object::long_value_offset = align_size_up((java_lang_boxing_object::hc_value_offset + header), BytesPerLong); // java_lang_ref_Reference: java_lang_ref_Reference::referent_offset = java_lang_ref_Reference::hc_referent_offset * x + header; @@ -2322,7 +2321,7 @@ java_lang_ref_Reference::number_of_fake_oop_fields = 1; // java_lang_ref_SoftReference Class - java_lang_ref_SoftReference::timestamp_offset = java_lang_ref_SoftReference::hc_timestamp_offset * x + header; + java_lang_ref_SoftReference::timestamp_offset = align_size_up((java_lang_ref_SoftReference::hc_timestamp_offset * x + header), BytesPerLong); // Don't multiply static fields because they are always in wordSize units java_lang_ref_SoftReference::static_clock_offset = java_lang_ref_SoftReference::hc_static_clock_offset * x; @@ -2469,6 +2468,9 @@ #define CHECK_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \ valid &= check_offset(klass_name, cpp_klass_name :: field_name ## _offset, #field_name, field_sig) +#define CHECK_LONG_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \ + valid &= check_offset(klass_name, cpp_klass_name :: long_ ## field_name ## _offset, #field_name, field_sig) + #define CHECK_STATIC_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \ valid &= check_static_offset(klass_name, cpp_klass_name :: static_ ## field_name ## _offset, #field_name, field_sig) @@ -2501,11 +2503,11 @@ CHECK_OFFSET("java/lang/Boolean", java_lang_boxing_object, value, "Z"); CHECK_OFFSET("java/lang/Character", java_lang_boxing_object, value, "C"); CHECK_OFFSET("java/lang/Float", java_lang_boxing_object, value, "F"); - CHECK_OFFSET("java/lang/Double", java_lang_boxing_object, value, "D"); + CHECK_LONG_OFFSET("java/lang/Double", java_lang_boxing_object, value, "D"); CHECK_OFFSET("java/lang/Byte", java_lang_boxing_object, value, "B"); CHECK_OFFSET("java/lang/Short", java_lang_boxing_object, value, "S"); CHECK_OFFSET("java/lang/Integer", java_lang_boxing_object, value, "I"); - CHECK_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J"); + CHECK_LONG_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J"); // java.lang.ClassLoader diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -653,6 +653,7 @@ hc_value_offset = 0 }; static int value_offset; + static int long_value_offset; static oop initialize_and_allocate(BasicType type, TRAPS); public: @@ -665,7 +666,10 @@ static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; } static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; } - static int value_offset_in_bytes() { return value_offset; } + static int value_offset_in_bytes(BasicType type) { + return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset : + value_offset; + } // Debugging friend class JavaClasses; @@ -747,7 +751,7 @@ public: enum { // The timestamp is a long field and may need to be adjusted for alignment. - hc_timestamp_offset = align_object_offset_(hc_discovered_offset + 1) + hc_timestamp_offset = hc_discovered_offset + 1 }; enum { hc_static_clock_offset = 0 diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -283,6 +283,7 @@ template(cache_field_name, "cache") \ template(value_name, "value") \ template(frontCacheEnabled_name, "frontCacheEnabled") \ + template(stringCacheEnabled_name, "stringCacheEnabled") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -564,6 +565,10 @@ do_name( copyOfRange_name, "copyOfRange") \ do_signature(copyOfRange_signature, "([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;") \ \ + do_intrinsic(_equalsC, java_util_Arrays, equals_name, equalsC_signature, F_S) \ + do_name( equals_name, "equals") \ + do_signature(equalsC_signature, "([C[C)Z") \ + \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \ /* (symbols invoke_name and invoke_signature defined above) */ \ \ diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -130,6 +130,7 @@ const size_t MIN_TREE_CHUNK_SIZE = sizeof(TreeChunk)/HeapWordSize; class BinaryTreeDictionary: public FreeBlockDictionary { + friend class VMStructs; bool _splay; size_t _totalSize; size_t _totalFreeBlocks; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -805,28 +805,30 @@ // This must be volatile, or else there is a danger that the compiler // will compile the code below into a sometimes-infinite loop, by keeping // the value read the first time in a register. - oop o = (oop)p; - volatile oop* second_word_addr = o->klass_addr(); while (true) { - klassOop k = (klassOop)(*second_word_addr); // We must do this until we get a consistent view of the object. - if (FreeChunk::secondWordIndicatesFreeChunk((intptr_t)k)) { - FreeChunk* fc = (FreeChunk*)p; - volatile size_t* sz_addr = (volatile size_t*)(fc->size_addr()); - size_t res = (*sz_addr); - klassOop k2 = (klassOop)(*second_word_addr); // Read to confirm. - if (k == k2) { + if (FreeChunk::indicatesFreeChunk(p)) { + volatile FreeChunk* fc = (volatile FreeChunk*)p; + size_t res = fc->size(); + // If the object is still a free chunk, return the size, else it + // has been allocated so try again. + if (FreeChunk::indicatesFreeChunk(p)) { assert(res != 0, "Block size should not be 0"); return res; } - } else if (k != NULL) { - assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop."); - assert(o->is_parsable(), "Should be parsable"); - assert(o->is_oop(true /* ignore mark word */), "Should be an oop."); - size_t res = o->size_given_klass(k->klass_part()); - res = adjustObjectSize(res); - assert(res != 0, "Block size should not be 0"); - return res; + } else { + // must read from what 'p' points to in each loop. + klassOop k = ((volatile oopDesc*)p)->klass_or_null(); + if (k != NULL) { + assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop."); + oop o = (oop)p; + assert(o->is_parsable(), "Should be parsable"); + assert(o->is_oop(true /* ignore mark word */), "Should be an oop."); + size_t res = o->size_given_klass(k->klass_part()); + res = adjustObjectSize(res); + assert(res != 0, "Block size should not be 0"); + return res; + } } } } @@ -845,31 +847,31 @@ // This must be volatile, or else there is a danger that the compiler // will compile the code below into a sometimes-infinite loop, by keeping // the value read the first time in a register. - oop o = (oop)p; - volatile oop* second_word_addr = o->klass_addr(); DEBUG_ONLY(uint loops = 0;) while (true) { - klassOop k = (klassOop)(*second_word_addr); // We must do this until we get a consistent view of the object. - if (FreeChunk::secondWordIndicatesFreeChunk((intptr_t)k)) { - FreeChunk* fc = (FreeChunk*)p; - volatile size_t* sz_addr = (volatile size_t*)(fc->size_addr()); - size_t res = (*sz_addr); - klassOop k2 = (klassOop)(*second_word_addr); // Read to confirm. - if (k == k2) { + if (FreeChunk::indicatesFreeChunk(p)) { + volatile FreeChunk* fc = (volatile FreeChunk*)p; + size_t res = fc->size(); + if (FreeChunk::indicatesFreeChunk(p)) { assert(res != 0, "Block size should not be 0"); assert(loops == 0, "Should be 0"); return res; } - } else if (k != NULL && o->is_parsable()) { - assert(k->is_oop(), "Should really be klass oop."); - assert(o->is_oop(), "Should be an oop"); - size_t res = o->size_given_klass(k->klass_part()); - res = adjustObjectSize(res); - assert(res != 0, "Block size should not be 0"); - return res; } else { - return c->block_size_if_printezis_bits(p); + // must read from what 'p' points to in each loop. + klassOop k = ((volatile oopDesc*)p)->klass_or_null(); + if (k != NULL && ((oopDesc*)p)->is_parsable()) { + assert(k->is_oop(), "Should really be klass oop."); + oop o = (oop)p; + assert(o->is_oop(), "Should be an oop"); + size_t res = o->size_given_klass(k->klass_part()); + res = adjustObjectSize(res); + assert(res != 0, "Block size should not be 0"); + return res; + } else { + return c->block_size_if_printezis_bits(p); + } } assert(loops == 0, "Can loop at most once"); DEBUG_ONLY(loops++;) @@ -907,9 +909,8 @@ // and those objects (if garbage) may have been modified to hold // live range information. // assert(ParallelGCThreads > 0 || _bt.block_start(p) == p, "Should be a block boundary"); - klassOop k = oop(p)->klass(); - intptr_t ki = (intptr_t)k; - if (FreeChunk::secondWordIndicatesFreeChunk(ki)) return false; + if (FreeChunk::indicatesFreeChunk(p)) return false; + klassOop k = oop(p)->klass_or_null(); if (k != NULL) { // Ignore mark word because it may have been used to // chain together promoted objects (the last one @@ -1027,7 +1028,7 @@ FreeChunk* fc = (FreeChunk*)res; fc->markNotFree(); assert(!fc->isFree(), "shouldn't be marked free"); - assert(oop(fc)->klass() == NULL, "should look uninitialized"); + assert(oop(fc)->klass_or_null() == NULL, "should look uninitialized"); // Verify that the block offset table shows this to // be a single block, but not one which is unallocated. _bt.verify_single_block(res, size); @@ -2593,7 +2594,7 @@ } res->markNotFree(); assert(!res->isFree(), "shouldn't be marked free"); - assert(oop(res)->klass() == NULL, "should look uninitialized"); + assert(oop(res)->klass_or_null() == NULL, "should look uninitialized"); // mangle a just allocated object with a distinct pattern. debug_only(res->mangleAllocated(word_sz)); return (HeapWord*)res; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -190,7 +190,8 @@ // depends on this property. debug_only( FreeChunk* junk = NULL; - assert(junk->prev_addr() == (void*)(oop(junk)->klass_addr()), + assert(UseCompressedOops || + junk->prev_addr() == (void*)(oop(junk)->klass_addr()), "Offset of FreeChunk::_prev within FreeChunk must match" " that of OopDesc::_klass within OopDesc"); ) @@ -1039,7 +1040,7 @@ // mark end of object } // check that oop looks uninitialized - assert(oop(start)->klass() == NULL, "_klass should be NULL"); + assert(oop(start)->klass_or_null() == NULL, "_klass should be NULL"); } void CMSCollector::promoted(bool par, HeapWord* start, @@ -1309,17 +1310,25 @@ } } oop obj = oop(obj_ptr); - assert(obj->klass() == NULL, "Object should be uninitialized here."); + assert(obj->klass_or_null() == NULL, "Object should be uninitialized here."); // Otherwise, copy the object. Here we must be careful to insert the // klass pointer last, since this marks the block as an allocated object. + // Except with compressed oops it's the mark word. HeapWord* old_ptr = (HeapWord*)old; if (word_sz > (size_t)oopDesc::header_size()) { Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(), obj_ptr + oopDesc::header_size(), word_sz - oopDesc::header_size()); } + + if (UseCompressedOops) { + // Copy gap missed by (aligned) header size calculation above + obj->set_klass_gap(old->klass_gap()); + } + // Restore the mark word copied above. obj->set_mark(m); + // Now we can track the promoted object, if necessary. We take care // To delay the transition from uninitialized to full object // (i.e., insertion of klass pointer) until after, so that it @@ -1327,7 +1336,8 @@ if (promoInfo->tracking()) { promoInfo->track((PromotedObject*)obj, old->klass()); } - // Finally, install the klass pointer. + + // Finally, install the klass pointer (this should be volatile). obj->set_klass(old->klass()); assert(old->is_oop(), "Will dereference klass ptr below"); @@ -6165,7 +6175,7 @@ HeapWord* CMSCollector::next_card_start_after_block(HeapWord* addr) const { size_t sz = 0; oop p = (oop)addr; - if (p->klass() != NULL && p->is_parsable()) { + if (p->klass_or_null() != NULL && p->is_parsable()) { sz = CompactibleFreeListSpace::adjustObjectSize(p->size()); } else { sz = block_size_using_printezis_bits(addr); @@ -6602,7 +6612,7 @@ } if (_bitMap->isMarked(addr)) { // it's marked; is it potentially uninitialized? - if (p->klass() != NULL) { + if (p->klass_or_null() != NULL) { if (CMSPermGenPrecleaningEnabled && !p->is_parsable()) { // Signal precleaning to redirty the card since // the klass pointer is already installed. @@ -6615,11 +6625,8 @@ if (p->is_objArray()) { // objArrays are precisely marked; restrict scanning // to dirty cards only. - size = p->oop_iterate(_scanningClosure, mr); - assert(size == CompactibleFreeListSpace::adjustObjectSize(size), - "adjustObjectSize should be the identity for array sizes, " - "which are necessarily larger than minimum object size of " - "two heap words"); + size = CompactibleFreeListSpace::adjustObjectSize( + p->oop_iterate(_scanningClosure, mr)); } else { // A non-array may have been imprecisely marked; we need // to scan object in its entirety. @@ -6653,7 +6660,7 @@ } } else { // Either a not yet marked object or an uninitialized object - if (p->klass() == NULL || !p->is_parsable()) { + if (p->klass_or_null() == NULL || !p->is_parsable()) { // An uninitialized object, skip to the next card, since // we may not be able to read its P-bits yet. assert(size == 0, "Initial value"); @@ -6710,7 +6717,7 @@ HeapWord* addr = (HeapWord*)p; DEBUG_ONLY(_collector->verify_work_stacks_empty();) assert(!_span.contains(addr), "we are scanning the survivor spaces"); - assert(p->klass() != NULL, "object should be initializd"); + assert(p->klass_or_null() != NULL, "object should be initializd"); assert(p->is_parsable(), "must be parsable."); // an initialized object; ignore mark word in verification below // since we are running concurrent with mutators @@ -6868,7 +6875,7 @@ assert(_skipBits == 0, "tautology"); _skipBits = 2; // skip next two marked bits ("Printezis-marks") oop p = oop(addr); - if (p->klass() == NULL || !p->is_parsable()) { + if (p->klass_or_null() == NULL || !p->is_parsable()) { DEBUG_ONLY(if (!_verifying) {) // We re-dirty the cards on which this object lies and increase // the _threshold so that we'll come back to scan this object @@ -6890,7 +6897,7 @@ if (_threshold < end_card_addr) { _threshold = end_card_addr; } - if (p->klass() != NULL) { + if (p->klass_or_null() != NULL) { // Redirty the range of cards... _mut->mark_range(redirty_range); } // ...else the setting of klass will dirty the card anyway. @@ -7048,7 +7055,7 @@ assert(_skip_bits == 0, "tautology"); _skip_bits = 2; // skip next two marked bits ("Printezis-marks") oop p = oop(addr); - if (p->klass() == NULL || !p->is_parsable()) { + if (p->klass_or_null() == NULL || !p->is_parsable()) { // in the case of Clean-on-Enter optimization, redirty card // and avoid clearing card by increasing the threshold. return; @@ -8023,7 +8030,7 @@ "alignment problem"); #ifdef DEBUG - if (oop(addr)->klass() != NULL && + if (oop(addr)->klass_or_null() != NULL && ( !_collector->should_unload_classes() || oop(addr)->is_parsable())) { // Ignore mark word because we are running concurrent with mutators @@ -8036,7 +8043,7 @@ } else { // This should be an initialized object that's alive. - assert(oop(addr)->klass() != NULL && + assert(oop(addr)->klass_or_null() != NULL && (!_collector->should_unload_classes() || oop(addr)->is_parsable()), "Should be an initialized object"); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -22,88 +22,6 @@ * */ -// -// Free block maintenance for Concurrent Mark Sweep Generation -// -// The main data structure for free blocks are -// . an indexed array of small free blocks, and -// . a dictionary of large free blocks -// - -// No virtuals in FreeChunk (don't want any vtables). - -// A FreeChunk is merely a chunk that can be in a doubly linked list -// and has a size field. NOTE: FreeChunks are distinguished from allocated -// objects in two ways (by the sweeper). The second word (prev) has the -// LSB set to indicate a free chunk; allocated objects' klass() pointers -// don't have their LSB set. The corresponding bit in the CMSBitMap is -// set when the chunk is allocated. There are also blocks that "look free" -// but are not part of the free list and should not be coalesced into larger -// free blocks. These free blocks have their two LSB's set. - -class FreeChunk VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - FreeChunk* _next; - FreeChunk* _prev; - size_t _size; - - public: - NOT_PRODUCT(static const size_t header_size();) - // Returns "true" if the "wrd", which is required to be the second word - // of a block, indicates that the block represents a free chunk. - static bool secondWordIndicatesFreeChunk(intptr_t wrd) { - return (wrd & 0x1) == 0x1; - } - bool isFree() const { - return secondWordIndicatesFreeChunk((intptr_t)_prev); - } - bool cantCoalesce() const { return (((intptr_t)_prev) & 0x3) == 0x3; } - FreeChunk* next() const { return _next; } - FreeChunk* prev() const { return (FreeChunk*)(((intptr_t)_prev) & ~(0x3)); } - debug_only(void* prev_addr() const { return (void*)&_prev; }) - - void linkAfter(FreeChunk* ptr) { - linkNext(ptr); - if (ptr != NULL) ptr->linkPrev(this); - } - void linkAfterNonNull(FreeChunk* ptr) { - assert(ptr != NULL, "precondition violation"); - linkNext(ptr); - ptr->linkPrev(this); - } - void linkNext(FreeChunk* ptr) { _next = ptr; } - void linkPrev(FreeChunk* ptr) { _prev = (FreeChunk*)((intptr_t)ptr | 0x1); } - void clearPrev() { _prev = NULL; } - void clearNext() { _next = NULL; } - void dontCoalesce() { - // the block should be free - assert(isFree(), "Should look like a free block"); - _prev = (FreeChunk*)(((intptr_t)_prev) | 0x2); - } - void markFree() { _prev = (FreeChunk*)((intptr_t)_prev | 0x1); } - void markNotFree() { _prev = NULL; } - - size_t size() const { return _size; } - void setSize(size_t size) { _size = size; } - - // For volatile reads: - size_t* size_addr() { return &_size; } - - // Return the address past the end of this chunk - HeapWord* end() const { return ((HeapWord*) this) + _size; } - - // debugging - void verify() const PRODUCT_RETURN; - void verifyList() const PRODUCT_RETURN; - void mangleAllocated(size_t size) PRODUCT_RETURN; - void mangleFreed(size_t size) PRODUCT_RETURN; -}; - -// Alignment helpers etc. -#define numQuanta(x,y) ((x+y-1)/y) -enum AlignmentConstants { - MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment -}; // A FreeBlockDictionary is an abstract superclass that will allow // a number of alternative implementations in the future. diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -47,15 +47,15 @@ Copy::fill_to_words(addr + hdr, size - hdr, baadbabeHeapWord); } -void FreeChunk::mangleFreed(size_t size) { +void FreeChunk::mangleFreed(size_t sz) { assert(baadbabeHeapWord != deadbeefHeapWord, "Need distinct patterns"); // mangle all but the header of a just-freed block of storage // just prior to passing it to the storage dictionary - assert(size >= MinChunkSize, "smallest size of object"); - assert(size == _size, "just checking"); + assert(sz >= MinChunkSize, "smallest size of object"); + assert(sz == size(), "just checking"); HeapWord* addr = (HeapWord*)this; size_t hdr = header_size(); - Copy::fill_to_words(addr + hdr, size - hdr, deadbeefHeapWord); + Copy::fill_to_words(addr + hdr, sz - hdr, deadbeefHeapWord); } void FreeChunk::verifyList() const { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -0,0 +1,137 @@ +/* + * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// +// Free block maintenance for Concurrent Mark Sweep Generation +// +// The main data structure for free blocks are +// . an indexed array of small free blocks, and +// . a dictionary of large free blocks +// + +// No virtuals in FreeChunk (don't want any vtables). + +// A FreeChunk is merely a chunk that can be in a doubly linked list +// and has a size field. NOTE: FreeChunks are distinguished from allocated +// objects in two ways (by the sweeper), depending on whether the VM is 32 or +// 64 bits. +// In 32 bits or 64 bits without CompressedOops, the second word (prev) has the +// LSB set to indicate a free chunk; allocated objects' klass() pointers +// don't have their LSB set. The corresponding bit in the CMSBitMap is +// set when the chunk is allocated. There are also blocks that "look free" +// but are not part of the free list and should not be coalesced into larger +// free blocks. These free blocks have their two LSB's set. + +class FreeChunk VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + // For 64 bit compressed oops, the markOop encodes both the size and the + // indication that this is a FreeChunk and not an object. + volatile size_t _size; + FreeChunk* _prev; + FreeChunk* _next; + + markOop mark() const volatile { return (markOop)_size; } + void set_mark(markOop m) { _size = (size_t)m; } + + public: + NOT_PRODUCT(static const size_t header_size();) + + // Returns "true" if the address indicates that the block represents + // a free chunk. + static bool indicatesFreeChunk(const HeapWord* addr) { + // Force volatile read from addr because value might change between + // calls. We really want the read of _mark and _prev from this pointer + // to be volatile but making the fields volatile causes all sorts of + // compilation errors. + return ((volatile FreeChunk*)addr)->isFree(); + } + + bool isFree() const volatile { + LP64_ONLY(if (UseCompressedOops) return mark()->is_cms_free_chunk(); else) + return (((intptr_t)_prev) & 0x1) == 0x1; + } + bool cantCoalesce() const { + assert(isFree(), "can't get coalesce bit on not free"); + return (((intptr_t)_prev) & 0x2) == 0x2; + } + void dontCoalesce() { + // the block should be free + assert(isFree(), "Should look like a free block"); + _prev = (FreeChunk*)(((intptr_t)_prev) | 0x2); + } + FreeChunk* prev() const { + return (FreeChunk*)(((intptr_t)_prev) & ~(0x3)); + } + + debug_only(void* prev_addr() const { return (void*)&_prev; }) + + size_t size() const volatile { + LP64_ONLY(if (UseCompressedOops) return mark()->get_size(); else ) + return _size; + } + void setSize(size_t sz) { + LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::set_size_and_free(sz)); else ) + _size = sz; + } + + FreeChunk* next() const { return _next; } + + void linkAfter(FreeChunk* ptr) { + linkNext(ptr); + if (ptr != NULL) ptr->linkPrev(this); + } + void linkAfterNonNull(FreeChunk* ptr) { + assert(ptr != NULL, "precondition violation"); + linkNext(ptr); + ptr->linkPrev(this); + } + void linkNext(FreeChunk* ptr) { _next = ptr; } + void linkPrev(FreeChunk* ptr) { + LP64_ONLY(if (UseCompressedOops) _prev = ptr; else) + _prev = (FreeChunk*)((intptr_t)ptr | 0x1); + } + void clearPrev() { _prev = NULL; } + void clearNext() { _next = NULL; } + void markNotFree() { + LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::prototype());) + // Also set _prev to null + _prev = NULL; + } + + // Return the address past the end of this chunk + HeapWord* end() const { return ((HeapWord*) this) + size(); } + + // debugging + void verify() const PRODUCT_RETURN; + void verifyList() const PRODUCT_RETURN; + void mangleAllocated(size_t size) PRODUCT_RETURN; + void mangleFreed(size_t size) PRODUCT_RETURN; +}; + +// Alignment helpers etc. +#define numQuanta(x,y) ((x+y-1)/y) +enum AlignmentConstants { + MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment +}; + diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -38,6 +38,7 @@ class FreeList VALUE_OBJ_CLASS_SPEC { friend class CompactibleFreeListSpace; + friend class VMStructs; friend class printTreeCensusClosure; FreeChunk* _head; // List of free chunks FreeChunk* _tail; // Tail of list of free chunks diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -23,6 +23,7 @@ */ #define VM_STRUCTS_CMS(nonstatic_field, \ + volatile_nonstatic_field, \ static_field) \ nonstatic_field(CompactibleFreeListSpace, _collector, CMSCollector*) \ nonstatic_field(CompactibleFreeListSpace, _bt, BlockOffsetArrayNonContigSpace) \ @@ -36,9 +37,17 @@ nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \ nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \ static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \ + volatile_nonstatic_field(FreeChunk, _size, size_t) \ nonstatic_field(FreeChunk, _next, FreeChunk*) \ nonstatic_field(FreeChunk, _prev, FreeChunk*) \ - nonstatic_field(FreeChunk, _size, size_t) + nonstatic_field(LinearAllocBlock, _word_size, size_t) \ + nonstatic_field(FreeList, _size, size_t) \ + nonstatic_field(FreeList, _count, ssize_t) \ + nonstatic_field(BinaryTreeDictionary, _totalSize, size_t) \ + nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary*) \ + nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ + nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) + #define VM_TYPES_CMS(declare_type, \ declare_toplevel_type) \ @@ -57,7 +66,14 @@ declare_toplevel_type(SurrogateLockerThread*) \ declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CMSCollector*) \ - declare_toplevel_type(FreeChunk*) + declare_toplevel_type(FreeChunk*) \ + declare_toplevel_type(BinaryTreeDictionary*) \ + declare_toplevel_type(FreeBlockDictionary*) \ + declare_toplevel_type(FreeList*) \ + declare_toplevel_type(FreeList) \ + declare_toplevel_type(LinearAllocBlock) \ + declare_toplevel_type(FreeBlockDictionary) \ + declare_type(BinaryTreeDictionary, FreeBlockDictionary) #define VM_INT_CONSTANTS_CMS(declare_constant) \ declare_constant(Generation::ConcurrentMarkSweep) \ diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep --- a/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Tue Jun 17 15:27:05 2008 -0700 @@ -206,6 +206,7 @@ freeBlockDictionary.hpp allocation.hpp freeBlockDictionary.hpp debug.hpp +freeBlockDictionary.hpp freeChunk.hpp freeBlockDictionary.hpp globalDefinitions.hpp freeBlockDictionary.hpp memRegion.hpp freeBlockDictionary.hpp mutex.hpp @@ -214,6 +215,14 @@ freeChunk.cpp copy.hpp freeChunk.cpp freeBlockDictionary.hpp +freeChunk.hpp allocation.hpp +freeChunk.hpp debug.hpp +freeChunk.hpp globalDefinitions.hpp +freeChunk.hpp markOop.hpp +freeChunk.hpp memRegion.hpp +freeChunk.hpp mutex.hpp +freeChunk.hpp ostream.hpp + freeList.cpp freeBlockDictionary.hpp freeList.cpp freeList.hpp freeList.cpp globals.hpp diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/includeDB_gc_shared --- a/src/share/vm/gc_implementation/includeDB_gc_shared Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/includeDB_gc_shared Tue Jun 17 15:27:05 2008 -0700 @@ -54,6 +54,7 @@ markSweep.inline.hpp psParallelCompact.hpp mutableNUMASpace.cpp mutableNUMASpace.hpp +mutableNUMASpace.cpp oop.inline.hpp mutableNUMASpace.cpp sharedHeap.hpp mutableNUMASpace.cpp thread_.inline.hpp diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1169,18 +1169,18 @@ // Trim off a prefix of at most objsFromOverflow items int i = 1; oop cur = prefix; - while (i < objsFromOverflow && cur->klass() != NULL) { + while (i < objsFromOverflow && cur->klass_or_null() != NULL) { i++; cur = oop(cur->klass()); } // Reattach remaining (suffix) to overflow list - if (cur->klass() != NULL) { + if (cur->klass_or_null() != NULL) { oop suffix = oop(cur->klass()); cur->set_klass_to_list_ptr(NULL); // Find last item of suffix list oop last = suffix; - while (last->klass() != NULL) { + while (last->klass_or_null() != NULL) { last = oop(last->klass()); } // Atomically prepend suffix to current overflow list diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/immutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/immutableSpace.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/immutableSpace.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -66,7 +66,7 @@ #endif -void ImmutableSpace::verify(bool allow_dirty) const { +void ImmutableSpace::verify(bool allow_dirty) { HeapWord* p = bottom(); HeapWord* t = end(); HeapWord* prev_p = NULL; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/immutableSpace.hpp --- a/src/share/vm/gc_implementation/shared/immutableSpace.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/immutableSpace.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -59,5 +59,5 @@ // Debugging virtual void print() const PRODUCT_RETURN; virtual void print_short() const PRODUCT_RETURN; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -599,12 +599,28 @@ // Mark the the holes in chunks below the top() as invalid. void MutableNUMASpace::set_top(HeapWord* value) { bool found_top = false; - for (int i = 0; i < lgrp_spaces()->length(); i++) { + for (int i = 0; i < lgrp_spaces()->length();) { LGRPSpace *ls = lgrp_spaces()->at(i); MutableSpace *s = ls->space(); HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom()); if (s->contains(value)) { + // Check if setting the chunk's top to a given value would create a hole less than + // a minimal object; assuming that's not the last chunk in which case we don't care. + if (i < lgrp_spaces()->length() - 1) { + size_t remainder = pointer_delta(s->end(), value); + const size_t minimal_object_size = oopDesc::header_size(); + if (remainder < minimal_object_size && remainder > 0) { + // Add a filler object of a minimal size, it will cross the chunk boundary. + SharedHeap::fill_region_with_object(MemRegion(value, minimal_object_size)); + value += minimal_object_size; + assert(!s->contains(value), "Should be in the next chunk"); + // Restart the loop from the same chunk, since the value has moved + // to the next one. + continue; + } + } + if (!os::numa_has_static_binding() && top < value && top < s->end()) { ls->add_invalid_region(MemRegion(top, value)); } @@ -620,6 +636,7 @@ s->set_top(s->end()); } } + i++; } MutableSpace::set_top(value); } @@ -700,12 +717,14 @@ MutableSpace *s = lgrp_spaces()->at(i)->space(); HeapWord *p = s->cas_allocate(size); if (p != NULL) { - size_t remainder = pointer_delta(s->end(), p); + size_t remainder = pointer_delta(s->end(), p + size); if (remainder < (size_t)oopDesc::header_size() && remainder > 0) { if (s->cas_deallocate(p, size)) { // We were the last to allocate and created a fragment less than // a minimal object. p = NULL; + } else { + guarantee(false, "Deallocation should always succeed"); } } } @@ -761,10 +780,12 @@ } } -void MutableNUMASpace::verify(bool allow_dirty) const { - for (int i = 0; i < lgrp_spaces()->length(); i++) { - lgrp_spaces()->at(i)->space()->verify(allow_dirty); - } +void MutableNUMASpace::verify(bool allow_dirty) { + // This can be called after setting an arbitary value to the space's top, + // so an object can cross the chunk boundary. We ensure the parsablity + // of the space and just walk the objects in linear fashion. + ensure_parsability(); + MutableSpace::verify(allow_dirty); } // Scan pages and gather stats about page placement and size. diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -192,7 +192,7 @@ // Debugging virtual void print_on(outputStream* st) const; virtual void print_short_on(outputStream* st) const; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); virtual void set_top(HeapWord* value); }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/mutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -118,7 +118,7 @@ bottom(), top(), end()); } -void MutableSpace::verify(bool allow_dirty) const { +void MutableSpace::verify(bool allow_dirty) { HeapWord* p = bottom(); HeapWord* t = top(); HeapWord* prev_p = NULL; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_implementation/shared/mutableSpace.hpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -98,5 +98,5 @@ virtual void print_on(outputStream* st) const; virtual void print_short() const; virtual void print_short_on(outputStream* st) const; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/gc_interface/collectedHeap.inline.hpp --- a/src/share/vm/gc_interface/collectedHeap.inline.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -90,11 +90,12 @@ HeapWord* obj, size_t size, int length) { + // Set array length before setting the _klass field + // in post_allocation_setup_common() because the klass field + // indicates that the object is parsable by concurrent GC. assert(length >= 0, "length should be non-negative"); + ((arrayOop)obj)->set_length(length); post_allocation_setup_common(klass, obj, size); - // Must set length after installing klass as set_klass zeros the length - // field in UseCompressedOops - ((arrayOop)obj)->set_length(length); assert(((oop)obj)->blueprint()->oop_is_array(), "must be an array"); // notify jvmti and dtrace (must be after length is set for dtrace) post_allocation_notify(klass, (oop)obj); @@ -224,6 +225,7 @@ assert(obj != NULL, "cannot initialize NULL object"); const size_t hs = oopDesc::header_size(); assert(size >= hs, "unexpected object size"); + ((oop)obj)->set_klass_gap(0); Copy::fill_to_aligned_words(obj + hs, size - hs); } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/includeDB_core --- a/src/share/vm/includeDB_core Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/includeDB_core Tue Jun 17 15:27:05 2008 -0700 @@ -3492,6 +3492,7 @@ relocInfo_.cpp assembler.inline.hpp relocInfo_.cpp assembler_.inline.hpp relocInfo_.cpp nativeInst_.hpp +relocInfo_.cpp oop.inline.hpp relocInfo_.cpp relocInfo.hpp relocInfo_.cpp safepoint.hpp diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1931,6 +1931,7 @@ } else { result->set_mark(markOopDesc::prototype()); } + result->set_klass_gap(0); result->set_klass(k_entry); SET_STACK_OBJECT(result, 0); UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml --- a/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Tue Jun 17 15:27:05 2008 -0700 @@ -1,7 +1,25 @@ diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl --- a/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Tue Jun 17 15:27:05 2008 -0700 @@ -1,10 +1,29 @@ + @@ -15,7 +34,6 @@ - diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/memory/space.cpp --- a/src/share/vm/memory/space.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/memory/space.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -815,6 +815,7 @@ "size for smallest fake object doesn't match"); instanceOop obj = (instanceOop) allocate(size); obj->set_mark(markOopDesc::prototype()); + obj->set_klass_gap(0); obj->set_klass(SystemDictionary::object_klass()); } } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/arrayOop.hpp --- a/src/share/vm/oops/arrayOop.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/arrayOop.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -41,11 +41,10 @@ // Header size computation. // The header is considered the oop part of this type plus the length. // Returns the aligned header_size_in_bytes. This is not equivalent to - // sizeof(arrayOopDesc) which should not appear in the code, except here. + // sizeof(arrayOopDesc) which should not appear in the code. static int header_size_in_bytes() { - size_t hs = UseCompressedOops ? - sizeof(arrayOopDesc) : - align_size_up(sizeof(arrayOopDesc) + sizeof(int), HeapWordSize); + size_t hs = align_size_up(length_offset_in_bytes() + sizeof(int), + HeapWordSize); #ifdef ASSERT // make sure it isn't called before UseCompressedOops is initialized. static size_t arrayoopdesc_hs = 0; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/instanceKlass.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -180,9 +180,8 @@ // End of the oop block. // - // number of words used by non-static fields in this klass (including - // inherited fields but after header_size()). If fields are compressed into - // header, this can be zero so it's not the same as number of static fields. + // Number of heapOopSize words used by non-static fields in this klass + // (including inherited fields but after header_size()). int _nonstatic_field_size; int _static_field_size; // number words used by static fields (oop and non-oop) in this klass int _static_oop_field_size;// number of static oop fields in this klass diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/instanceKlassKlass.cpp --- a/src/share/vm/oops/instanceKlassKlass.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -581,7 +581,7 @@ OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + ik->nonstatic_oop_map_size(); while (map < end_map) { - st->print("%d-%d ", map->offset(), map->offset() + oopSize*(map->length() - 1)); + st->print("%d-%d ", map->offset(), map->offset() + heapOopSize*(map->length() - 1)); map++; } st->cr(); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/instanceOop.hpp --- a/src/share/vm/oops/instanceOop.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/instanceOop.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -39,14 +39,7 @@ static bool contains_field_offset(int offset, int nonstatic_field_size) { int base_in_bytes = base_offset_in_bytes(); - if (UseCompressedOops) { - return (offset >= base_in_bytes && - // field can be embedded in header, or is after header. - (offset < (int)sizeof(instanceOopDesc) || - (offset-(int)sizeof(instanceOopDesc))/wordSize < nonstatic_field_size)); - } else { - return (offset >= base_in_bytes && - (offset-base_in_bytes)/wordSize < nonstatic_field_size); - } + return (offset >= base_in_bytes && + (offset-base_in_bytes) < nonstatic_field_size * heapOopSize); } }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/markOop.hpp --- a/src/share/vm/oops/markOop.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/markOop.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -29,8 +29,10 @@ // // Bit-format of an object header (most significant first): // -// -// unused:0/25 hash:25/31 age:4 biased_lock:1 lock:2 = 32/64 bits +// 32 bits: unused:0 hash:25 age:4 biased_lock:1 lock:2 +// 64 bits: unused:24 hash:31 cms:2 age:4 biased_lock:1 lock:2 +// unused:20 size:35 cms:2 age:4 biased_lock:1 lock:2 (if cms +// free chunk) // // - hash contains the identity hash value: largest value is // 31 bits, see os::random(). Also, 64-bit vm's require @@ -91,6 +93,7 @@ biased_lock_bits = 1, max_hash_bits = BitsPerWord - age_bits - lock_bits - biased_lock_bits, hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits, + cms_bits = LP64_ONLY(1) NOT_LP64(0), epoch_bits = 2 }; @@ -106,7 +109,8 @@ enum { lock_shift = 0, biased_lock_shift = lock_bits, age_shift = lock_bits + biased_lock_bits, - hash_shift = lock_bits + biased_lock_bits + age_bits, + cms_shift = age_shift + age_bits, + hash_shift = cms_shift + cms_bits, epoch_shift = hash_shift }; @@ -118,7 +122,9 @@ age_mask = right_n_bits(age_bits), age_mask_in_place = age_mask << age_shift, epoch_mask = right_n_bits(epoch_bits), - epoch_mask_in_place = epoch_mask << epoch_shift + epoch_mask_in_place = epoch_mask << epoch_shift, + cms_mask = right_n_bits(cms_bits), + cms_mask_in_place = cms_mask << cms_shift #ifndef _WIN64 ,hash_mask = right_n_bits(hash_bits), hash_mask_in_place = (address_word)hash_mask << hash_shift @@ -360,4 +366,40 @@ // see the definition in markOop.cpp for the gory details bool should_not_be_cached() const; + + // These markOops indicate cms free chunk blocks and not objects. + // In 64 bit, the markOop is set to distinguish them from oops. + // These are defined in 32 bit mode for vmStructs. + const static uintptr_t cms_free_chunk_pattern = 0x1; + + // Constants for the size field. + enum { size_shift = cms_shift + cms_bits, + size_bits = 35 // need for compressed oops 32G + }; + // These values are too big for Win64 + const static uintptr_t size_mask = LP64_ONLY(right_n_bits(size_bits)) + NOT_LP64(0); + const static uintptr_t size_mask_in_place = + (address_word)size_mask << size_shift; + +#ifdef _LP64 + static markOop cms_free_prototype() { + return markOop(((intptr_t)prototype() & ~cms_mask_in_place) | + ((cms_free_chunk_pattern & cms_mask) << cms_shift)); + } + uintptr_t cms_encoding() const { + return mask_bits(value() >> cms_shift, cms_mask); + } + bool is_cms_free_chunk() const { + return is_neutral() && + (cms_encoding() & cms_free_chunk_pattern) == cms_free_chunk_pattern; + } + + size_t get_size() const { return (size_t)(value() >> size_shift); } + static markOop set_size_and_free(size_t size) { + assert((size & ~size_mask) == 0, "shouldn't overflow size field"); + return markOop(((intptr_t)cms_free_prototype() & ~size_mask_in_place) | + (((intptr_t)size & size_mask) << size_shift)); + } +#endif // _LP64 }; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/methodDataOop.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -158,7 +158,6 @@ assert(ProfileTraps, "used only under +ProfileTraps"); uint old_flags = (_header._struct._flags & flag_mask); _header._struct._flags = (new_state << trap_shift) | old_flags; - assert(trap_state() == new_state, "sanity"); } u1 flags() { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/oop.hpp --- a/src/share/vm/oops/oop.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/oop.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -77,10 +77,15 @@ void init_mark(); klassOop klass() const; + klassOop klass_or_null() const volatile; oop* klass_addr(); narrowOop* compressed_klass_addr(); void set_klass(klassOop k); + + // For klass field compression + int klass_gap() const; + void set_klass_gap(int z); // For when the klass pointer is being used as a linked list "next" field. void set_klass_to_list_ptr(oop k); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/oops/oop.inline.hpp --- a/src/share/vm/oops/oop.inline.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/oops/oop.inline.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -36,7 +36,15 @@ inline klassOop oopDesc::klass() const { if (UseCompressedOops) { return (klassOop)decode_heap_oop_not_null(_metadata._compressed_klass); - // can be NULL in CMS, but isn't supported on CMS yet. + } else { + return _metadata._klass; + } +} + +inline klassOop oopDesc::klass_or_null() const volatile { + // can be NULL in CMS + if (UseCompressedOops) { + return (klassOop)decode_heap_oop(_metadata._compressed_klass); } else { return _metadata._klass; } @@ -64,15 +72,22 @@ assert(Universe::is_bootstrapping() || k != NULL, "must be a real klassOop"); assert(Universe::is_bootstrapping() || k->is_klass(), "not a klassOop"); if (UseCompressedOops) { - // zero the gap when the klass is set, by zeroing the pointer sized - // part of the union. - _metadata._klass = NULL; oop_store_without_check(compressed_klass_addr(), (oop)k); } else { oop_store_without_check(klass_addr(), (oop) k); } } +inline int oopDesc::klass_gap() const { + return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()); +} + +inline void oopDesc::set_klass_gap(int v) { + if (UseCompressedOops) { + *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()) = v; + } +} + inline void oopDesc::set_klass_to_list_ptr(oop k) { // This is only to be used during GC, for from-space objects, so no // barrier is needed. @@ -505,7 +520,7 @@ // try to find metaclass cycle safely without seg faulting on bad input // we should reach klassKlassObj by following klass link at most 3 times for (int i = 0; i < 3; i++) { - obj = obj->klass(); + obj = obj->klass_or_null(); // klass should be aligned and in permspace if (!check_obj_alignment(obj)) return false; if (!Universe::heap()->is_in_permanent(obj)) return false; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/c2_globals.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -390,5 +390,8 @@ \ product(intx, MaxLabelRootDepth, 1100, \ "Maximum times call Label_Root to prevent stack overflow") \ + \ + diagnostic(intx, DominatorSearchLimit, 1000, \ + "Iterations limit in Node::dominates") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/callnode.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -637,7 +637,7 @@ } Compile *C = phase->C; int offset = adrInst_t->offset(); - assert(offset >= 0, "should be valid offset"); + assert(adrInst_t->klass_is_exact() && offset >= 0, "should be valid offset"); ciKlass* adr_k = adrInst_t->klass(); assert(adr_k->is_loaded() && adr_k->is_java_klass() && @@ -674,12 +674,11 @@ ciKlass* at_k = at_ptr->klass(); if ((adrInst_t->base() == at_ptr->base()) && at_k->is_loaded() && - at_k->is_java_klass() && - !at_k->is_interface()) { + at_k->is_java_klass()) { // If we have found an argument matching addr_t, check if the field // at the specified offset is modified. - int at_idx = C->get_alias_index(at_ptr->add_offset(offset)->isa_oopptr()); - if (base_idx == at_idx && + if ((at_k->is_interface() || adr_k == at_k || + adr_k->is_subclass_of(at_k) && !at_ptr->klass_is_exact()) && (bcea == NULL || bcea->is_arg_modified(i - TypeFunc::Parms, offset, size))) { return true; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/callnode.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -388,9 +388,6 @@ void set_next_exception(SafePointNode* n); bool has_exceptions() const { return next_exception() != NULL; } - // Does this node have a use of n other than in debug information? - virtual bool has_non_debug_use(Node *n) {return false; } - // Standard Node stuff virtual int Opcode() const; virtual bool pinned() const { return true; } @@ -497,7 +494,7 @@ // Returns true if the call may modify n virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase); // Does this node have a use of n other than in debug information? - virtual bool has_non_debug_use(Node *n); + bool has_non_debug_use(Node *n); // Returns the unique CheckCastPP of a call // or result projection is there are several CheckCastPP // or returns NULL if there is no one. diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/cfgnode.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -707,8 +707,14 @@ //------------------------split_out_instance----------------------------------- // Split out an instance type from a bottom phi. PhiNode* PhiNode::split_out_instance(const TypePtr* at, PhaseIterGVN *igvn) const { - assert(type() == Type::MEMORY && (adr_type() == TypePtr::BOTTOM || - adr_type() == TypeRawPtr::BOTTOM) , "bottom or raw memory required"); + const TypeOopPtr *t_oop = at->isa_oopptr(); + assert(t_oop != NULL && t_oop->is_instance(), "expecting instance oopptr"); + const TypePtr *t = adr_type(); + assert(type() == Type::MEMORY && + (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM || + t->isa_oopptr() && !t->is_oopptr()->is_instance() && + t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop), + "bottom or raw memory required"); // Check if an appropriate node already exists. Node *region = in(0); @@ -1342,7 +1348,7 @@ Node *n = phi->in(i); if( !n ) return NULL; if( phase->type(n) == Type::TOP ) return NULL; - if( n->Opcode() == Op_ConP ) + if( n->Opcode() == Op_ConP || n->Opcode() == Op_ConN ) break; } if( i >= phi->req() ) // Only split for constants @@ -1615,64 +1621,6 @@ if (opt != NULL) return opt; } - if (in(1) != NULL && in(1)->Opcode() == Op_AddP && can_reshape) { - // Try to undo Phi of AddP: - // (Phi (AddP base base y) (AddP base2 base2 y)) - // becomes: - // newbase := (Phi base base2) - // (AddP newbase newbase y) - // - // This occurs as a result of unsuccessful split_thru_phi and - // interferes with taking advantage of addressing modes. See the - // clone_shift_expressions code in matcher.cpp - Node* addp = in(1); - const Type* type = addp->in(AddPNode::Base)->bottom_type(); - Node* y = addp->in(AddPNode::Offset); - if (y != NULL && addp->in(AddPNode::Base) == addp->in(AddPNode::Address)) { - // make sure that all the inputs are similar to the first one, - // i.e. AddP with base == address and same offset as first AddP - bool doit = true; - for (uint i = 2; i < req(); i++) { - if (in(i) == NULL || - in(i)->Opcode() != Op_AddP || - in(i)->in(AddPNode::Base) != in(i)->in(AddPNode::Address) || - in(i)->in(AddPNode::Offset) != y) { - doit = false; - break; - } - // Accumulate type for resulting Phi - type = type->meet(in(i)->in(AddPNode::Base)->bottom_type()); - } - Node* base = NULL; - if (doit) { - // Check for neighboring AddP nodes in a tree. - // If they have a base, use that it. - for (DUIterator_Fast kmax, k = this->fast_outs(kmax); k < kmax; k++) { - Node* u = this->fast_out(k); - if (u->is_AddP()) { - Node* base2 = u->in(AddPNode::Base); - if (base2 != NULL && !base2->is_top()) { - if (base == NULL) - base = base2; - else if (base != base2) - { doit = false; break; } - } - } - } - } - if (doit) { - if (base == NULL) { - base = new (phase->C, in(0)->req()) PhiNode(in(0), type, NULL); - for (uint i = 1; i < req(); i++) { - base->init_req(i, in(i)->in(AddPNode::Base)); - } - phase->is_IterGVN()->register_new_node_with_optimizer(base); - } - return new (phase->C, 4) AddPNode(base, base, y); - } - } - } - // Split phis through memory merges, so that the memory merges will go away. // Piggy-back this transformation on the search for a unique input.... // It will be as if the merged memory is the unique value of the phi. diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/chaitin.cpp --- a/src/share/vm/opto/chaitin.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/chaitin.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1385,7 +1385,7 @@ cisc->ins_req(1,src); // Requires a memory edge } b->_nodes.map(j,cisc); // Insert into basic block - n->replace_by(cisc); // Correct graph + n->subsume_by(cisc); // Correct graph // ++_used_cisc_instructions; #ifndef PRODUCT diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/classes.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -37,6 +37,7 @@ macro(AllocateArray) macro(AndI) macro(AndL) +macro(AryEq) macro(AtanD) macro(Binary) macro(Bool) @@ -64,6 +65,7 @@ macro(CMoveI) macro(CMoveL) macro(CMoveP) +macro(CMoveN) macro(CmpN) macro(CmpD) macro(CmpD3) @@ -133,6 +135,7 @@ macro(LoadF) macro(LoadI) macro(LoadKlass) +macro(LoadNKlass) macro(LoadL) macro(LoadL_unaligned) macro(LoadPLocked) diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/compile.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -368,7 +368,12 @@ BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size); // Record the buffer blob for next time. set_scratch_buffer_blob(blob); - guarantee(scratch_buffer_blob() != NULL, "Need BufferBlob for code generation"); + // Have we run out of code space? + if (scratch_buffer_blob() == NULL) { + // Let CompilerBroker disable further compilations. + record_failure("Not enough space for scratch buffer in CodeCache"); + return; + } // Initialize the relocation buffers relocInfo* locs_buf = (relocInfo*) blob->instructions_end() - MAX_locs_size; @@ -1065,6 +1070,8 @@ // No constant oop pointers (such as Strings); they alias with // unknown strings. tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); + } else if( to->is_instance_field() ) { + tj = to; // Keep NotNull and klass_is_exact for instance type } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) { // During the 2nd round of IterGVN, NotNull castings are removed. // Make sure the Bottom and NotNull variants alias the same. @@ -1084,7 +1091,7 @@ } else { ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset); if (!k->equals(canonical_holder) || tj->offset() != offset) { - tj = to = TypeInstPtr::make(TypePtr::BotPTR, canonical_holder, false, NULL, offset, to->instance_id()); + tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset, to->instance_id()); } } } @@ -1835,6 +1842,7 @@ // Implement items 1-5 from final_graph_reshaping below. static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { + if ( n->outcnt() == 0 ) return; // dead node uint nop = n->Opcode(); // Check for 2-input instruction with "last use" on right input. @@ -1901,7 +1909,7 @@ break; case Op_Opaque1: // Remove Opaque Nodes before matching case Op_Opaque2: // Remove Opaque Nodes before matching - n->replace_by(n->in(1)); + n->subsume_by(n->in(1)); break; case Op_CallStaticJava: case Op_CallJava: @@ -1961,6 +1969,7 @@ case Op_LoadC: case Op_LoadI: case Op_LoadKlass: + case Op_LoadNKlass: case Op_LoadL: case Op_LoadL_unaligned: case Op_LoadPLocked: @@ -1983,14 +1992,94 @@ } case Op_AddP: { // Assert sane base pointers - const Node *addp = n->in(AddPNode::Address); + Node *addp = n->in(AddPNode::Address); assert( !addp->is_AddP() || addp->in(AddPNode::Base)->is_top() || // Top OK for allocation addp->in(AddPNode::Base) == n->in(AddPNode::Base), "Base pointers must match" ); +#ifdef _LP64 + if (UseCompressedOops && + addp->Opcode() == Op_ConP && + addp == n->in(AddPNode::Base) && + n->in(AddPNode::Offset)->is_Con()) { + // Use addressing with narrow klass to load with offset on x86. + // On sparc loading 32-bits constant and decoding it have less + // instructions (4) then load 64-bits constant (7). + // Do this transformation here since IGVN will convert ConN back to ConP. + const Type* t = addp->bottom_type(); + if (t->isa_oopptr()) { + Node* nn = NULL; + + // Look for existing ConN node of the same exact type. + Compile* C = Compile::current(); + Node* r = C->root(); + uint cnt = r->outcnt(); + for (uint i = 0; i < cnt; i++) { + Node* m = r->raw_out(i); + if (m!= NULL && m->Opcode() == Op_ConN && + m->bottom_type()->is_narrowoop()->make_oopptr() == t) { + nn = m; + break; + } + } + if (nn != NULL) { + // Decode a narrow oop to match address + // [R12 + narrow_oop_reg<<3 + offset] + nn = new (C, 2) DecodeNNode(nn, t); + n->set_req(AddPNode::Base, nn); + n->set_req(AddPNode::Address, nn); + if (addp->outcnt() == 0) { + addp->disconnect_inputs(NULL); + } + } + } + } +#endif break; } +#ifdef _LP64 + case Op_CmpP: + // Do this transformation here to preserve CmpPNode::sub() and + // other TypePtr related Ideal optimizations (for example, ptr nullness). + if( n->in(1)->is_DecodeN() ) { + Compile* C = Compile::current(); + Node* in2 = NULL; + if( n->in(2)->is_DecodeN() ) { + in2 = n->in(2)->in(1); + } else if ( n->in(2)->Opcode() == Op_ConP ) { + const Type* t = n->in(2)->bottom_type(); + if (t == TypePtr::NULL_PTR) { + Node *in1 = n->in(1); + if (Matcher::clone_shift_expressions) { + // x86, ARM and friends can handle 2 adds in addressing mode. + // Decode a narrow oop and do implicit NULL check in address + // [R12 + narrow_oop_reg<<3 + offset] + in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); + } else { + // Don't replace CmpP(o ,null) if 'o' is used in AddP + // to generate implicit NULL check on Sparc where + // narrow oops can't be used in address. + uint i = 0; + for (; i < in1->outcnt(); i++) { + if (in1->raw_out(i)->is_AddP()) + break; + } + if (i >= in1->outcnt()) { + in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); + } + } + } else if (t->isa_oopptr()) { + in2 = ConNode::make(C, t->is_oopptr()->make_narrowoop()); + } + } + if( in2 != NULL ) { + Node* cmpN = new (C, 3) CmpNNode(n->in(1)->in(1), in2); + n->subsume_by( cmpN ); + } + } +#endif + case Op_ModI: if (UseDivMod) { // Check if a%b and a/b both exist @@ -2000,13 +2089,13 @@ Compile* C = Compile::current(); if (Matcher::has_match_rule(Op_DivModI)) { DivModINode* divmod = DivModINode::make(C, n); - d->replace_by(divmod->div_proj()); - n->replace_by(divmod->mod_proj()); + d->subsume_by(divmod->div_proj()); + n->subsume_by(divmod->mod_proj()); } else { // replace a%b with a-((a/b)*b) Node* mult = new (C, 3) MulINode(d, d->in(2)); Node* sub = new (C, 3) SubINode(d->in(1), mult); - n->replace_by( sub ); + n->subsume_by( sub ); } } } @@ -2021,13 +2110,13 @@ Compile* C = Compile::current(); if (Matcher::has_match_rule(Op_DivModL)) { DivModLNode* divmod = DivModLNode::make(C, n); - d->replace_by(divmod->div_proj()); - n->replace_by(divmod->mod_proj()); + d->subsume_by(divmod->div_proj()); + n->subsume_by(divmod->mod_proj()); } else { // replace a%b with a-((a/b)*b) Node* mult = new (C, 3) MulLNode(d, d->in(2)); Node* sub = new (C, 3) SubLNode(d->in(1), mult); - n->replace_by( sub ); + n->subsume_by( sub ); } } } @@ -2073,7 +2162,7 @@ // Replace many operand PackNodes with a binary tree for matching PackNode* p = (PackNode*) n; Node* btp = p->binaryTreePack(Compile::current(), 1, n->req()); - n->replace_by(btp); + n->subsume_by(btp); } break; default: diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/connode.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -35,16 +35,16 @@ //------------------------------make------------------------------------------- ConNode *ConNode::make( Compile* C, const Type *t ) { - if (t->isa_narrowoop()) return new (C, 1) ConNNode( t->is_narrowoop() ); switch( t->basic_type() ) { case T_INT: return new (C, 1) ConINode( t->is_int() ); - case T_ARRAY: return new (C, 1) ConPNode( t->is_aryptr() ); case T_LONG: return new (C, 1) ConLNode( t->is_long() ); case T_FLOAT: return new (C, 1) ConFNode( t->is_float_constant() ); case T_DOUBLE: return new (C, 1) ConDNode( t->is_double_constant() ); case T_VOID: return new (C, 1) ConNode ( Type::TOP ); case T_OBJECT: return new (C, 1) ConPNode( t->is_oopptr() ); + case T_ARRAY: return new (C, 1) ConPNode( t->is_aryptr() ); case T_ADDRESS: return new (C, 1) ConPNode( t->is_ptr() ); + case T_NARROWOOP: return new (C, 1) ConNNode( t->is_narrowoop() ); // Expected cases: TypePtr::NULL_PTR, any is_rawptr() // Also seen: AnyPtr(TopPTR *+top); from command line: // r -XX:+PrintOpto -XX:CIStart=285 -XX:+CompileTheWorld -XX:CompileTheWorldStartAt=660 @@ -185,6 +185,7 @@ case T_LONG: return new (C, 4) CMoveLNode( bol, left, right, t->is_long() ); case T_OBJECT: return new (C, 4) CMovePNode( c, bol, left, right, t->is_oopptr() ); case T_ADDRESS: return new (C, 4) CMovePNode( c, bol, left, right, t->is_ptr() ); + case T_NARROWOOP: return new (C, 4) CMoveNNode( c, bol, left, right, t ); default: ShouldNotReachHere(); return NULL; @@ -556,7 +557,7 @@ const Type *t = phase->type( in(1) ); if( t == Type::TOP ) return in(1); - if (in(1)->Opcode() == Op_EncodeP) { + if (in(1)->is_EncodeP()) { // (DecodeN (EncodeP p)) -> p return in(1)->in(1); } @@ -570,16 +571,19 @@ return bottom_type(); } -Node* DecodeNNode::decode(PhaseGVN* phase, Node* value) { - if (value->Opcode() == Op_EncodeP) { +Node* DecodeNNode::decode(PhaseTransform* phase, Node* value) { + if (value->is_EncodeP()) { // (DecodeN (EncodeP p)) -> p return value->in(1); } const Type* newtype = value->bottom_type(); if (newtype == TypeNarrowOop::NULL_PTR) { return phase->transform(new (phase->C, 1) ConPNode(TypePtr::NULL_PTR)); + } else if (newtype->isa_narrowoop()) { + return phase->transform(new (phase->C, 2) DecodeNNode(value, newtype->is_narrowoop()->make_oopptr())); } else { - return phase->transform(new (phase->C, 2) DecodeNNode(value, newtype->is_narrowoop()->make_oopptr())); + ShouldNotReachHere(); + return NULL; // to make C++ compiler happy. } } @@ -587,7 +591,7 @@ const Type *t = phase->type( in(1) ); if( t == Type::TOP ) return in(1); - if (in(1)->Opcode() == Op_DecodeN) { + if (in(1)->is_DecodeN()) { // (EncodeP (DecodeN p)) -> p return in(1)->in(1); } @@ -601,8 +605,8 @@ return bottom_type(); } -Node* EncodePNode::encode(PhaseGVN* phase, Node* value) { - if (value->Opcode() == Op_DecodeN) { +Node* EncodePNode::encode(PhaseTransform* phase, Node* value) { + if (value->is_DecodeN()) { // (EncodeP (DecodeN p)) -> p return value->in(1); } @@ -617,6 +621,9 @@ } } +Node *EncodePNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); +} //============================================================================= //------------------------------Identity--------------------------------------- diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/connode.hpp --- a/src/share/vm/opto/connode.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/connode.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -70,11 +70,6 @@ else return new (C, 1) ConPNode( TypeRawPtr::make(con) ); } - - static ConPNode* make( Compile *C, ciObject* con ) { - return new (C, 1) ConPNode( TypeOopPtr::make_from_constant(con) ); - } - }; @@ -84,11 +79,6 @@ public: ConNNode( const TypeNarrowOop *t ) : ConNode(t) {} virtual int Opcode() const; - - static ConNNode* make( Compile *C, ciObject* con ) { - return new (C, 1) ConNNode( TypeNarrowOop::make_from_constant(con) ); - } - }; @@ -210,7 +200,14 @@ virtual int Opcode() const; }; -//------------------------------ConstraintCastNode------------------------------------- +//------------------------------CMoveNNode------------------------------------- +class CMoveNNode : public CMoveNode { +public: + CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } + virtual int Opcode() const; +}; + +//------------------------------ConstraintCastNode----------------------------- // cast to a different range class ConstraintCastNode: public TypeNode { public: @@ -274,6 +271,7 @@ public: EncodePNode(Node* value, const Type* type): TypeNode(type, 2) { + init_class_id(Class_EncodeP); init_req(0, NULL); init_req(1, value); } @@ -282,7 +280,8 @@ virtual const Type *Value( PhaseTransform *phase ) const; virtual uint ideal_reg() const { return Op_RegN; } - static Node* encode(PhaseGVN* phase, Node* value); + static Node* encode(PhaseTransform* phase, Node* value); + virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); }; //------------------------------DecodeN-------------------------------- @@ -293,6 +292,7 @@ public: DecodeNNode(Node* value, const Type* type): TypeNode(type, 2) { + init_class_id(Class_DecodeN); init_req(0, NULL); init_req(1, value); } @@ -301,7 +301,7 @@ virtual const Type *Value( PhaseTransform *phase ) const; virtual uint ideal_reg() const { return Op_RegP; } - static Node* decode(PhaseGVN* phase, Node* value); + static Node* decode(PhaseTransform* phase, Node* value); }; //------------------------------Conv2BNode------------------------------------- diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/doCall.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -580,7 +580,7 @@ Node* ex_klass_node = NULL; if (has_ex_handler() && !ex_type->klass_is_exact()) { Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes()); - ex_klass_node = _gvn.transform(new (C, 3) LoadKlassNode(NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); + ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a LoadKlass from the 'ex_node'. @@ -592,7 +592,7 @@ ex_klass_node = new (C, ex_node->req()) PhiNode( ex_node->in(0), TypeKlassPtr::OBJECT ); for( uint i = 1; i < ex_node->req(); i++ ) { Node* p = basic_plus_adr( ex_node->in(i), ex_node->in(i), oopDesc::klass_offset_in_bytes() ); - Node* k = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); + Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); ex_klass_node->init_req( i, k ); } _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/escape.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -417,11 +417,18 @@ // | | // AddP ( base == address ) // + // case #8. narrow Klass's field reference. + // LoadNKlass + // | + // DecodeN + // | | + // AddP ( base == address ) + // Node *base = addp->in(AddPNode::Base)->uncast(); if (base->is_top()) { // The AddP case #3 and #6. base = addp->in(AddPNode::Address)->uncast(); assert(base->Opcode() == Op_ConP || base->Opcode() == Op_ThreadLocal || - base->Opcode() == Op_CastX2P || + base->Opcode() == Op_CastX2P || base->is_DecodeN() || (base->is_Mem() && base->bottom_type() == TypeRawPtr::NOTNULL) || (base->is_Proj() && base->in(0)->is_Allocate()), "sanity"); } @@ -888,6 +895,23 @@ record_for_optimizer(n); if (alloc->is_Allocate() && ptn->_scalar_replaceable && (t->isa_instptr() || t->isa_aryptr())) { + + // First, put on the worklist all Field edges from Connection Graph + // which is more accurate then putting immediate users from Ideal Graph. + for (uint e = 0; e < ptn->edge_count(); e++) { + Node *use = _nodes->adr_at(ptn->edge_target(e))->_node; + assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(), + "only AddP nodes are Field edges in CG"); + if (use->outcnt() > 0) { // Don't process dead nodes + Node* addp2 = find_second_addp(use, use->in(AddPNode::Base)); + if (addp2 != NULL) { + assert(alloc->is_AllocateArray(),"array allocation was expected"); + alloc_worklist.append_if_missing(addp2); + } + alloc_worklist.append_if_missing(use); + } + } + // An allocation may have an Initialize which has raw stores. Scan // the users of the raw allocation result and push AddP users // on alloc_worklist. @@ -919,6 +943,8 @@ tinst = igvn->type(base)->isa_oopptr(); } else if (n->is_Phi() || n->is_CheckCastPP() || + n->is_EncodeP() || + n->is_DecodeN() || (n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) { if (visited.test_set(n->_idx)) { assert(n->is_Phi(), "loops only through Phi's"); @@ -935,13 +961,25 @@ tinst = igvn->type(val)->isa_oopptr(); assert(tinst != NULL && tinst->is_instance() && tinst->instance_id() == elem , "instance type expected."); - const TypeOopPtr *tn_t = igvn->type(tn)->isa_oopptr(); + + const TypeOopPtr *tn_t = NULL; + const Type *tn_type = igvn->type(tn); + if (tn_type->isa_narrowoop()) { + tn_t = tn_type->is_narrowoop()->make_oopptr()->isa_oopptr(); + } else { + tn_t = tn_type->isa_oopptr(); + } if (tn_t != NULL && tinst->cast_to_instance(TypeOopPtr::UNKNOWN_INSTANCE)->higher_equal(tn_t)) { + if (tn_type->isa_narrowoop()) { + tn_type = tinst->make_narrowoop(); + } else { + tn_type = tinst; + } igvn->hash_delete(tn); - igvn->set_type(tn, tinst); - tn->set_type(tinst); + igvn->set_type(tn, tn_type); + tn->set_type(tn_type); igvn->hash_insert(tn); record_for_optimizer(n); } @@ -978,6 +1016,8 @@ alloc_worklist.append_if_missing(use); } else if (use->is_Phi() || use->is_CheckCastPP() || + use->is_EncodeP() || + use->is_DecodeN() || (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) { alloc_worklist.append_if_missing(use); } @@ -1199,7 +1239,7 @@ void ConnectionGraph::compute_escape() { - // 1. Populate Connection Graph with Ideal nodes. + // 1. Populate Connection Graph (CG) with Ideal nodes. Unique_Node_List worklist_init; worklist_init.map(_compile->unique(), NULL); // preallocate space @@ -1281,11 +1321,13 @@ remove_deferred(ni, &deferred_edges, &visited); if (n->is_AddP()) { // If this AddP computes an address which may point to more that one - // object, nothing the address points to can be scalar replaceable. + // object or more then one field (array's element), nothing the address + // points to can be scalar replaceable. Node *base = get_addp_base(n); ptset.Clear(); PointsTo(ptset, base, igvn); - if (ptset.Size() > 1) { + if (ptset.Size() > 1 || + (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) { for( VectorSetI j(&ptset); j.test(); ++j ) { uint pt = j.elem; ptnode_adr(pt)->_scalar_replaceable = false; @@ -1538,6 +1580,7 @@ if (k->Opcode() == Op_LoadKlass) { kt = k->as_Load()->type()->isa_klassptr(); } else { + // Also works for DecodeN(LoadNKlass). kt = k->as_Type()->type()->isa_klassptr(); } assert(kt != NULL, "TypeKlassPtr required."); @@ -1776,6 +1819,7 @@ break; } case Op_LoadKlass: + case Op_LoadNKlass: { add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, true); break; @@ -1979,12 +2023,18 @@ assert(false, "Op_ConP"); break; } + case Op_ConN: + { + assert(false, "Op_ConN"); + break; + } case Op_CreateEx: { assert(false, "Op_CreateEx"); break; } case Op_LoadKlass: + case Op_LoadNKlass: { assert(false, "Op_LoadKlass"); break; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/graphKit.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -532,7 +532,7 @@ C->log()->elem("hot_throw preallocated='1' reason='%s'", Deoptimization::trap_reason_name(reason)); const TypeInstPtr* ex_con = TypeInstPtr::make(ex_obj); - Node* ex_node = _gvn.transform(new (C, 1) ConPNode(ex_con)); + Node* ex_node = _gvn.transform( ConNode::make(C, ex_con) ); // Clear the detail message of the preallocated exception object. // Weblogic sometimes mutates the detail message of exceptions @@ -1043,7 +1043,7 @@ Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != NULL) return akls; Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - return _gvn.transform( new (C, 3) LoadKlassNode(0, immutable_memory(), k_adr, TypeInstPtr::KLASS) ); + return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) ); } //-------------------------load_array_length----------------------------------- @@ -2210,7 +2210,7 @@ // cache which is mutable so can't use immutable memory. Other // types load from the super-class display table which is immutable. Node *kmem = might_be_cache ? memory(p2) : immutable_memory(); - Node *nkls = _gvn.transform( new (C, 3) LoadKlassNode( NULL, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) ); + Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) ); // Compile speed common case: ARE a subtype and we canNOT fail if( superklass == nkls ) @@ -2801,7 +2801,6 @@ // initialization, and source them from the new InitializeNode. // This will allow us to observe initializations when they occur, // and link them properly (as a group) to the InitializeNode. - Node* klass_node = alloc->in(AllocateNode::KlassNode); assert(init->in(InitializeNode::Memory) == malloc, ""); MergeMemNode* minit_in = MergeMemNode::make(C, malloc); init->set_req(InitializeNode::Memory, minit_in); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/lcm.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -113,6 +113,7 @@ case Op_LoadN: case Op_LoadS: case Op_LoadKlass: + case Op_LoadNKlass: case Op_LoadRange: case Op_LoadD_unaligned: case Op_LoadL_unaligned: @@ -133,6 +134,7 @@ if( mach->in(2) != val ) continue; break; // Found a memory op? case Op_StrComp: + case Op_AryEq: // Not a legit memory op for implicit null check regardless of // embedded loads continue; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/library_call.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -163,6 +163,7 @@ bool inline_native_newArray(); bool inline_native_getLength(); bool inline_array_copyOf(bool is_copyOfRange); + bool inline_array_equals(); bool inline_native_clone(bool is_virtual); bool inline_native_Reflection_getCallerClass(); bool inline_native_AtomicLong_get(); @@ -259,6 +260,7 @@ switch (id) { case vmIntrinsics::_indexOf: case vmIntrinsics::_compareTo: + case vmIntrinsics::_equalsC: break; // InlineNatives does not control String.compareTo default: return NULL; @@ -272,6 +274,9 @@ case vmIntrinsics::_indexOf: if (!SpecialStringIndexOf) return NULL; break; + case vmIntrinsics::_equalsC: + if (!SpecialArraysEquals) return NULL; + break; case vmIntrinsics::_arraycopy: if (!InlineArrayCopy) return NULL; break; @@ -586,6 +591,8 @@ return inline_array_copyOf(false); case vmIntrinsics::_copyOfRange: return inline_array_copyOf(true); + case vmIntrinsics::_equalsC: + return inline_array_equals(); case vmIntrinsics::_clone: return inline_native_clone(intrinsic()->is_virtual()); @@ -813,6 +820,24 @@ return true; } +//------------------------------inline_array_equals---------------------------- +bool LibraryCallKit::inline_array_equals() { + + if (!Matcher::has_match_rule(Op_AryEq)) return false; + + _sp += 2; + Node *argument2 = pop(); + Node *argument1 = pop(); + + Node* equals = + _gvn.transform(new (C, 3) AryEqNode(control(), + argument1, + argument2) + ); + push(equals); + return true; +} + // Java version of String.indexOf(constant string) // class StringDecl { // StringDecl(char[] ca) { @@ -896,7 +921,7 @@ Node* sourcea = basic_plus_adr(string_object, string_object, value_offset); Node* source = make_load(no_ctrl, sourcea, source_type, T_OBJECT, string_type->add_offset(value_offset)); - Node* target = _gvn.transform(ConPNode::make(C, target_array)); + Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array)) ); jint target_length = target_array->length(); const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin)); const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot); @@ -2168,7 +2193,7 @@ // (They don't if CAS fails, but it isn't worth checking.) pre_barrier(control(), base, adr, alias_idx, newval, value_type, T_OBJECT); #ifdef _LP64 - if (adr->bottom_type()->is_narrow()) { + if (adr->bottom_type()->is_ptr_to_narrowoop()) { cas = _gvn.transform(new (C, 5) CompareAndSwapNNode(control(), mem, adr, EncodePNode::encode(&_gvn, newval), EncodePNode::encode(&_gvn, oldval))); @@ -2454,7 +2479,7 @@ if (region == NULL) never_see_null = true; Node* p = basic_plus_adr(mirror, offset); const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL; - Node* kls = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); + Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type) ); _sp += nargs; // any deopt will start just before call to enclosing method Node* null_ctl = top(); kls = null_check_oop(kls, &null_ctl, never_see_null); @@ -2634,7 +2659,7 @@ phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, Klass::super_offset_in_bytes() + sizeof(oopDesc)); - kls = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); + kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL) ); null_ctl = top(); kls = null_check_oop(kls, &null_ctl); if (null_ctl != top()) { @@ -2720,7 +2745,7 @@ args[which_arg] = _gvn.transform(arg); Node* p = basic_plus_adr(arg, class_klass_offset); - Node* kls = new (C, 3) LoadKlassNode(0, immutable_memory(), p, adr_type, kls_type); + Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type); klasses[which_arg] = _gvn.transform(kls); } @@ -2838,6 +2863,8 @@ _sp += nargs; // set original stack for use by uncommon_trap mirror = do_null_check(mirror, T_OBJECT); _sp -= nargs; + // If mirror or obj is dead, only null-path is taken. + if (stopped()) return true; enum { _normal_path = 1, _slow_path = 2, PATH_LIMIT }; RegionNode* result_reg = new(C, PATH_LIMIT) RegionNode(PATH_LIMIT); @@ -3827,24 +3854,22 @@ if (!stopped()) { // Copy the fastest available way. // (No need for PreserveJVMState, since we're using it all up now.) + // TODO: generate fields/elements copies for small objects instead. Node* src = obj; Node* dest = raw_obj; - Node* end = dest; Node* size = _gvn.transform(alloc_siz); // Exclude the header. int base_off = instanceOopDesc::base_offset_in_bytes(); if (UseCompressedOops) { - // copy the header gap though. - Node* sptr = basic_plus_adr(src, base_off); - Node* dptr = basic_plus_adr(dest, base_off); - Node* sval = make_load(control(), sptr, TypeInt::INT, T_INT, raw_adr_type); - store_to_memory(control(), dptr, sval, T_INT, raw_adr_type); - base_off += sizeof(int); + assert(base_off % BytesPerLong != 0, "base with compressed oops"); + // With compressed oops base_offset_in_bytes is 12 which creates + // the gap since countx is rounded by 8 bytes below. + // Copy klass and the gap. + base_off = instanceOopDesc::klass_offset_in_bytes(); } src = basic_plus_adr(src, base_off); dest = basic_plus_adr(dest, base_off); - end = basic_plus_adr(end, size); // Compute the length also, if needed: Node* countx = size; @@ -4388,7 +4413,7 @@ // (At this point we can assume disjoint_bases, since types differ.) int ek_offset = objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc); Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = new (C, 3) LoadKlassNode(0, immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* n1 = LoadKlassNode::make(_gvn, immutable_memory(), p1, TypeRawPtr::BOTTOM); Node* dest_elem_klass = _gvn.transform(n1); Node* cv = generate_checkcast_arraycopy(adr_type, dest_elem_klass, diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/loopnode.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -2632,6 +2632,7 @@ case Op_LoadD_unaligned: case Op_LoadL_unaligned: case Op_StrComp: // Does a bunch of load-like effects + case Op_AryEq: pinned = false; } if( pinned ) { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/loopopts.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -464,6 +464,7 @@ case T_FLOAT: case T_DOUBLE: case T_ADDRESS: // (RawPtr) + case T_NARROWOOP: cost++; break; case T_OBJECT: { // Base oops are OK, but not derived oops diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/macro.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -458,7 +458,7 @@ } } else if (use->is_SafePoint()) { SafePointNode* sfpt = use->as_SafePoint(); - if (sfpt->has_non_debug_use(res)) { + if (sfpt->is_Call() && sfpt->as_Call()->has_non_debug_use(res)) { // Object is passed as argument. DEBUG_ONLY(disq_node = use;) NOT_PRODUCT(fail_eliminate = "Object is passed as argument";) @@ -1282,12 +1282,6 @@ } rawmem = make_store(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, T_ADDRESS); - if (UseCompressedOops) { - Node *zeronode = makecon(TypeInt::ZERO); - // store uncompressed 0 into klass ptr to zero out gap. The gap is - // used for primitive fields and has to be zeroed. - rawmem = make_store(control, rawmem, object, oopDesc::klass_gap_offset_in_bytes(), zeronode, T_INT); - } rawmem = make_store(control, rawmem, object, oopDesc::klass_offset_in_bytes(), klass_node, T_OBJECT); int header_size = alloc->minimum_header_size(); // conservatively small diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/matcher.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -52,7 +52,7 @@ #ifdef ASSERT _old2new_map(C->comp_arena()), #endif - _shared_constants(C->comp_arena()), + _shared_nodes(C->comp_arena()), _reduceOp(reduceOp), _leftOp(leftOp), _rightOp(rightOp), _swallowed(swallowed), _begin_inst_chain_rule(_BEGIN_INST_CHAIN_RULE), @@ -744,6 +744,7 @@ if (nidx == Compile::AliasIdxBot && midx == Compile::AliasIdxTop) { switch (n->Opcode()) { case Op_StrComp: + case Op_AryEq: case Op_MemBarVolatile: case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type? nidx = Compile::AliasIdxTop; @@ -880,7 +881,7 @@ Node *m = n->in(i); // Get input int op = m->Opcode(); assert((op == Op_BoxLock) == jvms->is_monitor_use(i), "boxes only at monitor sites"); - if( op == Op_ConI || op == Op_ConP || + if( op == Op_ConI || op == Op_ConP || op == Op_ConN || op == Op_ConF || op == Op_ConD || op == Op_ConL // || op == Op_BoxLock // %%%% enable this and remove (+++) in chaitin.cpp ) { @@ -1191,7 +1192,7 @@ uint cnt = n->req(); uint start = 1; if( mem != (Node*)1 ) start = MemNode::Memory+1; - if( n->Opcode() == Op_AddP ) { + if( n->is_AddP() ) { assert( mem == (Node*)1, "" ); start = AddPNode::Base+1; } @@ -1219,7 +1220,7 @@ if( t->singleton() ) { // Never force constants into registers. Allow them to match as // constants or registers. Copies of the same value will share - // the same register. See find_shared_constant. + // the same register. See find_shared_node. return false; } else { // Not a constant // Stop recursion if they have different Controls. @@ -1243,12 +1244,10 @@ if( j == max_scan ) // No post-domination before scan end? return true; // Then break the match tree up } - - if (m->Opcode() == Op_DecodeN && m->outcnt() == 2) { + if (m->is_DecodeN() && Matcher::clone_shift_expressions) { // These are commonly used in address expressions and can - // efficiently fold into them in some cases but because they are - // consumed by AddP they commonly have two users. - if (m->raw_out(0) == m->raw_out(1) && m->raw_out(0)->Opcode() == Op_AddP) return false; + // efficiently fold into them on X64 in some cases. + return false; } } @@ -1368,13 +1367,16 @@ // which reduces the number of copies of a constant in the final // program. The register allocator is free to split uses later to // split live ranges. -MachNode* Matcher::find_shared_constant(Node* leaf, uint rule) { - if (!leaf->is_Con()) return NULL; +MachNode* Matcher::find_shared_node(Node* leaf, uint rule) { + if (!leaf->is_Con() && !leaf->is_DecodeN()) return NULL; // See if this Con has already been reduced using this rule. - if (_shared_constants.Size() <= leaf->_idx) return NULL; - MachNode* last = (MachNode*)_shared_constants.at(leaf->_idx); + if (_shared_nodes.Size() <= leaf->_idx) return NULL; + MachNode* last = (MachNode*)_shared_nodes.at(leaf->_idx); if (last != NULL && rule == last->rule()) { + // Don't expect control change for DecodeN + if (leaf->is_DecodeN()) + return last; // Get the new space root. Node* xroot = new_node(C->root()); if (xroot == NULL) { @@ -1420,9 +1422,9 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { assert( rule >= NUM_OPERANDS, "called with operand rule" ); - MachNode* shared_con = find_shared_constant(s->_leaf, rule); - if (shared_con != NULL) { - return shared_con; + MachNode* shared_node = find_shared_node(s->_leaf, rule); + if (shared_node != NULL) { + return shared_node; } // Build the object to represent this state & prepare for recursive calls @@ -1447,7 +1449,7 @@ mach->ins_req(MemNode::Memory,mem); // If the _leaf is an AddP, insert the base edge - if( leaf->Opcode() == Op_AddP ) + if( leaf->is_AddP() ) mach->ins_req(AddPNode::Base,leaf->in(AddPNode::Base)); uint num_proj = _proj_list.size(); @@ -1475,9 +1477,9 @@ guarantee(_proj_list.size() == num_proj, "no allocation during spill generation"); } - if (leaf->is_Con()) { + if (leaf->is_Con() || leaf->is_DecodeN()) { // Record the con for sharing - _shared_constants.map(leaf->_idx, ex); + _shared_nodes.map(leaf->_idx, ex); } return ex; @@ -1716,6 +1718,7 @@ mstack.push(n->in(0), Pre_Visit); // Visit Control input continue; // while (mstack.is_nonempty()) case Op_StrComp: + case Op_AryEq: set_shared(n); // Force result into register (it will be anyways) break; case Op_ConP: { // Convert pointers above the centerline to NUL @@ -1726,6 +1729,14 @@ } break; } + case Op_ConN: { // Convert narrow pointers above the centerline to NUL + TypeNode *tn = n->as_Type(); // Constants derive from type nodes + const TypePtr* tp = tn->type()->is_narrowoop()->make_oopptr(); + if (tp->_ptr == TypePtr::AnyNull) { + tn->set_type(TypeNarrowOop::NULL_PTR); + } + break; + } case Op_Binary: // These are introduced in the Post_Visit state. ShouldNotReachHere(); break; @@ -1760,6 +1771,7 @@ case Op_LoadF: case Op_LoadI: case Op_LoadKlass: + case Op_LoadNKlass: case Op_LoadL: case Op_LoadS: case Op_LoadP: @@ -1817,7 +1829,7 @@ Node *adr = m->in(AddPNode::Address); // Intel, ARM and friends can handle 2 adds in addressing mode - if( clone_shift_expressions && adr->Opcode() == Op_AddP && + if( clone_shift_expressions && adr->is_AddP() && // AtomicAdd is not an addressing expression. // Cheap to find it by looking for screwy base. !adr->in(AddPNode::Base)->is_top() ) { @@ -1891,6 +1903,7 @@ case Op_CMoveF: case Op_CMoveI: case Op_CMoveL: + case Op_CMoveN: case Op_CMoveP: { // Restructure into a binary tree for Matching. It's possible that // we could move this code up next to the graph reshaping for IfNodes diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/matcher.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -48,7 +48,7 @@ void ReduceOper( State *s, int newrule, Node *&mem, MachNode *mach ); // If this node already matched using "rule", return the MachNode for it. - MachNode* find_shared_constant(Node* con, uint rule); + MachNode* find_shared_node(Node* n, uint rule); // Convert a dense opcode number to an expanded rule number const int *_reduceOp; @@ -81,7 +81,7 @@ Node_List &_proj_list; // For Machine nodes killing many values - Node_Array _shared_constants; + Node_Array _shared_nodes; debug_only(Node_Array _old2new_map;) // Map roots of ideal-trees to machine-roots diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/memnode.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -133,7 +133,9 @@ PhiNode *mphi = result->as_Phi(); assert(mphi->bottom_type() == Type::MEMORY, "memory phi required"); const TypePtr *t = mphi->adr_type(); - if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM) { + if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM || + t->isa_oopptr() && !t->is_oopptr()->is_instance() && + t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop) { // clone the Phi with our address type result = mphi->split_out_instance(t_adr, igvn); } else { @@ -154,7 +156,7 @@ phase->C->must_alias(adr_check, alias_idx ); // Sometimes dead array references collapse to a[-1], a[-2], or a[-3] if( !consistent && adr_check != NULL && !adr_check->empty() && - tp->isa_aryptr() && tp->offset() == Type::OffsetBot && + tp->isa_aryptr() && tp->offset() == Type::OffsetBot && adr_check->isa_aryptr() && adr_check->offset() != Type::OffsetBot && ( adr_check->offset() == arrayOopDesc::length_offset_in_bytes() || adr_check->offset() == oopDesc::klass_offset_in_bytes() || @@ -251,21 +253,31 @@ if (dom == NULL || dom->is_top() || sub == NULL || sub->is_top()) return false; // Conservative answer for dead code - // Check 'dom'. + // Check 'dom'. Skip Proj and CatchProj nodes. dom = dom->find_exact_control(dom); if (dom == NULL || dom->is_top()) return false; // Conservative answer for dead code - if (dom->is_Start() || dom->is_Root() || dom == sub) + if (dom == sub) { + // For the case when, for example, 'sub' is Initialize and the original + // 'dom' is Proj node of the 'sub'. + return false; + } + + if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) return true; // 'dom' dominates 'sub' if its control edge and control edges // of all its inputs dominate or equal to sub's control edge. // Currently 'sub' is either Allocate, Initialize or Start nodes. - assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start(), "expecting only these nodes"); + // Or Region for the check in LoadNode::Ideal(); + // 'sub' should have sub->in(0) != NULL. + assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start() || + sub->is_Region(), "expecting only these nodes"); // Get control edge of 'sub'. + Node* orig_sub = sub; sub = sub->find_exact_control(sub->in(0)); if (sub == NULL || sub->is_top()) return false; // Conservative answer for dead code @@ -291,14 +303,16 @@ for (uint next = 0; next < dom_list.size(); next++) { Node* n = dom_list.at(next); + if (n == orig_sub) + return false; // One of dom's inputs dominated by sub. if (!n->is_CFG() && n->pinned()) { // Check only own control edge for pinned non-control nodes. n = n->find_exact_control(n->in(0)); if (n == NULL || n->is_top()) return false; // Conservative answer for dead code assert(n->is_CFG(), "expecting control"); - } - if (n->is_Start() || n->is_Root()) { + dom_list.push(n); + } else if (n->is_Con() || n->is_Start() || n->is_Root()) { only_dominating_controls = true; } else if (n->is_CFG()) { if (n->dominates(sub, nlist)) @@ -308,12 +322,11 @@ } else { // First, own control edge. Node* m = n->find_exact_control(n->in(0)); - if (m == NULL) - continue; - if (m->is_top()) - return false; // Conservative answer for dead code - dom_list.push(m); - + if (m != NULL) { + if (m->is_top()) + return false; // Conservative answer for dead code + dom_list.push(m); + } // Now, the rest of edges. uint cnt = n->req(); for (uint i = 1; i < cnt; i++) { @@ -577,6 +590,9 @@ // Find any cast-away of null-ness and keep its control. Null cast-aways are // going away in this pass and we need to make this memory op depend on the // gating null check. +Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + return Ideal_common_DU_postCCP(ccp, this, in(MemNode::Address)); +} // I tried to leave the CastPP's in. This makes the graph more accurate in // some sense; we get to keep around the knowledge that an oop is not-null @@ -586,15 +602,14 @@ // some of the more trivial cases in the optimizer. Removing more useless // Phi's started allowing Loads to illegally float above null checks. I gave // up on this approach. CNC 10/20/2000 -Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - Node *ctr = in(MemNode::Control); - Node *mem = in(MemNode::Memory); - Node *adr = in(MemNode::Address); +// This static method may be called not from MemNode (EncodePNode calls it). +// Only the control edge of the node 'n' might be updated. +Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) { Node *skipped_cast = NULL; // Need a null check? Regular static accesses do not because they are // from constant addresses. Array ops are gated by the range check (which // always includes a NULL check). Just check field ops. - if( !ctr ) { + if( n->in(MemNode::Control) == NULL ) { // Scan upwards for the highest location we can place this memory op. while( true ) { switch( adr->Opcode() ) { @@ -619,10 +634,10 @@ } // CastPP is going away in this pass! We need this memory op to be // control-dependent on the test that is guarding the CastPP. - ccp->hash_delete(this); - set_req(MemNode::Control, adr->in(0)); - ccp->hash_insert(this); - return this; + ccp->hash_delete(n); + n->set_req(MemNode::Control, adr->in(0)); + ccp->hash_insert(n); + return n; case Op_Phi: // Attempt to float above a Phi to some dominating point. @@ -653,10 +668,10 @@ adr = adr->in(1); continue; } - ccp->hash_delete(this); - set_req(MemNode::Control, adr->in(0)); - ccp->hash_insert(this); - return this; + ccp->hash_delete(n); + n->set_req(MemNode::Control, adr->in(0)); + ccp->hash_insert(n); + return n; // List of "safe" opcodes; those that implicitly block the memory // op below any null check. @@ -665,10 +680,13 @@ case Op_LoadP: // Loading from within a klass case Op_LoadN: // Loading from within a klass case Op_LoadKlass: // Loading from within a klass + case Op_LoadNKlass: // Loading from within a klass case Op_ConP: // Loading from a klass + case Op_ConN: // Loading from a klass case Op_CreateEx: // Sucking up the guts of an exception oop case Op_Con: // Reading from TLS case Op_CMoveP: // CMoveP is pinned + case Op_CMoveN: // CMoveN is pinned break; // No progress case Op_Proj: // Direct call to an allocation routine @@ -677,8 +695,8 @@ { assert(adr->as_Proj()->_con == TypeFunc::Parms, "must be return value"); const Node* call = adr->in(0); - if (call->is_CallStaticJava()) { - const CallStaticJavaNode* call_java = call->as_CallStaticJava(); + if (call->is_CallJava()) { + const CallJavaNode* call_java = call->as_CallJava(); const TypeTuple *r = call_java->tf()->range(); assert(r->cnt() > TypeFunc::Parms, "must return value"); const Type* ret_type = r->field_at(TypeFunc::Parms); @@ -750,7 +768,7 @@ case T_ADDRESS: return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_ptr() ); case T_OBJECT: #ifdef _LP64 - if (adr->bottom_type()->is_narrow()) { + if (adr->bottom_type()->is_ptr_to_narrowoop()) { const TypeNarrowOop* narrowtype; if (rt->isa_narrowoop()) { narrowtype = rt->is_narrowoop(); @@ -762,10 +780,10 @@ return DecodeNNode::decode(&gvn, load); } else #endif - { - assert(!adr->bottom_type()->is_narrow(), "should have got back a narrow oop"); - return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr()); - } + { + assert(!adr->bottom_type()->is_ptr_to_narrowoop(), "should have got back a narrow oop"); + return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr()); + } } ShouldNotReachHere(); return (LoadNode*)NULL; @@ -1119,6 +1137,127 @@ return NULL; } +//------------------------------split_through_phi------------------------------ +// Split instance field load through Phi. +Node *LoadNode::split_through_phi(PhaseGVN *phase) { + Node* mem = in(MemNode::Memory); + Node* address = in(MemNode::Address); + const TypePtr *addr_t = phase->type(address)->isa_ptr(); + const TypeOopPtr *t_oop = addr_t->isa_oopptr(); + + assert(mem->is_Phi() && (t_oop != NULL) && + t_oop->is_instance_field(), "invalide conditions"); + + Node *region = mem->in(0); + if (region == NULL) { + return NULL; // Wait stable graph + } + uint cnt = mem->req(); + for( uint i = 1; i < cnt; i++ ) { + Node *in = mem->in(i); + if( in == NULL ) { + return NULL; // Wait stable graph + } + } + // Check for loop invariant. + if (cnt == 3) { + for( uint i = 1; i < cnt; i++ ) { + Node *in = mem->in(i); + Node* m = MemNode::optimize_memory_chain(in, addr_t, phase); + if (m == mem) { + set_req(MemNode::Memory, mem->in(cnt - i)); // Skip this phi. + return this; + } + } + } + // Split through Phi (see original code in loopopts.cpp). + assert(phase->C->have_alias_type(addr_t), "instance should have alias type"); + + // Do nothing here if Identity will find a value + // (to avoid infinite chain of value phis generation). + if ( !phase->eqv(this, this->Identity(phase)) ) + return NULL; + + // Skip the split if the region dominates some control edge of the address. + if (cnt == 3 && !MemNode::all_controls_dominate(address, region)) + return NULL; + + const Type* this_type = this->bottom_type(); + int this_index = phase->C->get_alias_index(addr_t); + int this_offset = addr_t->offset(); + int this_iid = addr_t->is_oopptr()->instance_id(); + int wins = 0; + PhaseIterGVN *igvn = phase->is_IterGVN(); + Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); + for( uint i = 1; i < region->req(); i++ ) { + Node *x; + Node* the_clone = NULL; + if( region->in(i) == phase->C->top() ) { + x = phase->C->top(); // Dead path? Use a dead data op + } else { + x = this->clone(); // Else clone up the data op + the_clone = x; // Remember for possible deletion. + // Alter data node to use pre-phi inputs + if( this->in(0) == region ) { + x->set_req( 0, region->in(i) ); + } else { + x->set_req( 0, NULL ); + } + for( uint j = 1; j < this->req(); j++ ) { + Node *in = this->in(j); + if( in->is_Phi() && in->in(0) == region ) + x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone + } + } + // Check for a 'win' on some paths + const Type *t = x->Value(igvn); + + bool singleton = t->singleton(); + + // See comments in PhaseIdealLoop::split_thru_phi(). + if( singleton && t == Type::TOP ) { + singleton &= region->is_Loop() && (i != LoopNode::EntryControl); + } + + if( singleton ) { + wins++; + x = igvn->makecon(t); + } else { + // We now call Identity to try to simplify the cloned node. + // Note that some Identity methods call phase->type(this). + // Make sure that the type array is big enough for + // our new node, even though we may throw the node away. + // (This tweaking with igvn only works because x is a new node.) + igvn->set_type(x, t); + Node *y = x->Identity(igvn); + if( y != x ) { + wins++; + x = y; + } else { + y = igvn->hash_find(x); + if( y ) { + wins++; + x = y; + } else { + // Else x is a new node we are keeping + // We do not need register_new_node_with_optimizer + // because set_type has already been called. + igvn->_worklist.push(x); + } + } + } + if (x != the_clone && the_clone != NULL) + igvn->remove_dead_node(the_clone); + phi->set_req(i, x); + } + if( wins > 0 ) { + // Record Phi + igvn->register_new_node_with_optimizer(phi); + return phi; + } + igvn->remove_dead_node(phi); + return NULL; +} //------------------------------Ideal------------------------------------------ // If the load is from Field memory and the pointer is non-null, we can @@ -1176,112 +1315,9 @@ const TypeOopPtr *t_oop = addr_t->isa_oopptr(); if (can_reshape && opt_mem->is_Phi() && (t_oop != NULL) && t_oop->is_instance_field()) { - assert(t_oop->offset() != Type::OffsetBot && t_oop->offset() != Type::OffsetTop, ""); - Node *region = opt_mem->in(0); - uint cnt = opt_mem->req(); - for( uint i = 1; i < cnt; i++ ) { - Node *in = opt_mem->in(i); - if( in == NULL ) { - region = NULL; // Wait stable graph - break; - } - } - if (region != NULL) { - // Check for loop invariant. - if (cnt == 3) { - for( uint i = 1; i < cnt; i++ ) { - Node *in = opt_mem->in(i); - Node* m = MemNode::optimize_memory_chain(in, addr_t, phase); - if (m == opt_mem) { - set_req(MemNode::Memory, opt_mem->in(cnt - i)); // Skip this phi. - return this; - } - } - } - // Split through Phi (see original code in loopopts.cpp). - assert(phase->C->have_alias_type(addr_t), "instance should have alias type"); - - // Do nothing here if Identity will find a value - // (to avoid infinite chain of value phis generation). - if ( !phase->eqv(this, this->Identity(phase)) ) - return NULL; - - const Type* this_type = this->bottom_type(); - int this_index = phase->C->get_alias_index(addr_t); - int this_offset = addr_t->offset(); - int this_iid = addr_t->is_oopptr()->instance_id(); - int wins = 0; - PhaseIterGVN *igvn = phase->is_IterGVN(); - Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); - for( uint i = 1; i < region->req(); i++ ) { - Node *x; - Node* the_clone = NULL; - if( region->in(i) == phase->C->top() ) { - x = phase->C->top(); // Dead path? Use a dead data op - } else { - x = this->clone(); // Else clone up the data op - the_clone = x; // Remember for possible deletion. - // Alter data node to use pre-phi inputs - if( this->in(0) == region ) { - x->set_req( 0, region->in(i) ); - } else { - x->set_req( 0, NULL ); - } - for( uint j = 1; j < this->req(); j++ ) { - Node *in = this->in(j); - if( in->is_Phi() && in->in(0) == region ) - x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone - } - } - // Check for a 'win' on some paths - const Type *t = x->Value(igvn); - - bool singleton = t->singleton(); - - // See comments in PhaseIdealLoop::split_thru_phi(). - if( singleton && t == Type::TOP ) { - singleton &= region->is_Loop() && (i != LoopNode::EntryControl); - } - - if( singleton ) { - wins++; - x = igvn->makecon(t); - } else { - // We now call Identity to try to simplify the cloned node. - // Note that some Identity methods call phase->type(this). - // Make sure that the type array is big enough for - // our new node, even though we may throw the node away. - // (This tweaking with igvn only works because x is a new node.) - igvn->set_type(x, t); - Node *y = x->Identity(igvn); - if( y != x ) { - wins++; - x = y; - } else { - y = igvn->hash_find(x); - if( y ) { - wins++; - x = y; - } else { - // Else x is a new node we are keeping - // We do not need register_new_node_with_optimizer - // because set_type has already been called. - igvn->_worklist.push(x); - } - } - } - if (x != the_clone && the_clone != NULL) - igvn->remove_dead_node(the_clone); - phi->set_req(i, x); - } - if( wins > 0 ) { - // Record Phi - igvn->register_new_node_with_optimizer(phi); - return phi; - } else { - igvn->remove_dead_node(phi); - } - } + // Split instance field load through Phi. + Node* result = split_through_phi(phase); + if (result != NULL) return result; } } @@ -1585,8 +1621,31 @@ } //============================================================================= +//----------------------------LoadKlassNode::make------------------------------ +// Polymorphic factory method: +Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) { + Compile* C = gvn.C; + Node *ctl = NULL; + // sanity check the alias category against the created node type + const TypeOopPtr *adr_type = adr->bottom_type()->isa_oopptr(); + assert(adr_type != NULL, "expecting TypeOopPtr"); +#ifdef _LP64 + if (adr_type->is_ptr_to_narrowoop()) { + const TypeNarrowOop* narrowtype = tk->is_oopptr()->make_narrowoop(); + Node* load_klass = gvn.transform(new (C, 3) LoadNKlassNode(ctl, mem, adr, at, narrowtype)); + return DecodeNNode::decode(&gvn, load_klass); + } +#endif + assert(!adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop"); + return new (C, 3) LoadKlassNode(ctl, mem, adr, at, tk); +} + //------------------------------Value------------------------------------------ const Type *LoadKlassNode::Value( PhaseTransform *phase ) const { + return klass_value_common(phase); +} + +const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP const Type *t1 = phase->type( in(MemNode::Memory) ); if (t1 == Type::TOP) return Type::TOP; @@ -1718,6 +1777,10 @@ // To clean up reflective code, simplify k.java_mirror.as_klass to plain k. // Also feed through the klass in Allocate(...klass...)._klass. Node* LoadKlassNode::Identity( PhaseTransform *phase ) { + return klass_identity_common(phase); +} + +Node* LoadNode::klass_identity_common(PhaseTransform *phase ) { Node* x = LoadNode::Identity(phase); if (x != this) return x; @@ -1776,6 +1839,34 @@ return this; } + +//------------------------------Value------------------------------------------ +const Type *LoadNKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = klass_value_common(phase); + + if (t == TypePtr::NULL_PTR) { + return TypeNarrowOop::NULL_PTR; + } + if (t != Type::TOP && !t->isa_narrowoop()) { + assert(t->is_oopptr(), "sanity"); + t = t->is_oopptr()->make_narrowoop(); + } + return t; +} + +//------------------------------Identity--------------------------------------- +// To clean up reflective code, simplify k.java_mirror.as_klass to narrow k. +// Also feed through the klass in Allocate(...klass...)._klass. +Node* LoadNKlassNode::Identity( PhaseTransform *phase ) { + Node *x = klass_identity_common(phase); + + const Type *t = phase->type( x ); + if( t == Type::TOP ) return x; + if( t->isa_narrowoop()) return x; + + return EncodePNode::encode(phase, x); +} + //------------------------------Value----------------------------------------- const Type *LoadRangeNode::Value( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP @@ -1836,7 +1927,7 @@ case T_ADDRESS: case T_OBJECT: #ifdef _LP64 - if (adr->bottom_type()->is_narrow() || + if (adr->bottom_type()->is_ptr_to_narrowoop() || (UseCompressedOops && val->bottom_type()->isa_klassptr() && adr->bottom_type()->isa_rawptr())) { const TypePtr* type = val->bottom_type()->is_ptr(); @@ -2312,6 +2403,13 @@ return remove_dead_region(phase, can_reshape) ? this : NULL; } +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *AryEqNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/memnode.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -72,7 +72,8 @@ // This one should probably be a phase-specific function: static bool all_controls_dominate(Node* dom, Node* sub); - // Is this Node a MemNode or some descendent? Default is YES. + // Find any cast-away of null-ness and keep its control. + static Node *Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ); virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); virtual const class TypePtr *adr_type() const; // returns bottom_type of address @@ -150,6 +151,9 @@ // zero out the control input. virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + // Split instance field load through Phi. + Node* split_through_phi(PhaseGVN *phase); + // Recover original value from boxed values Node *eliminate_autobox(PhaseGVN *phase); @@ -157,6 +161,10 @@ // then call the virtual add() to set the type. virtual const Type *Value( PhaseTransform *phase ) const; + // Common methods for LoadKlass and LoadNKlass nodes. + const Type *klass_value_common( PhaseTransform *phase ) const; + Node *klass_identity_common( PhaseTransform *phase ); + virtual uint ideal_reg() const; virtual const Type *bottom_type() const; // Following method is copied from TypeNode: @@ -358,14 +366,35 @@ // Load a Klass from an object class LoadKlassNode : public LoadPNode { public: - LoadKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk = TypeKlassPtr::OBJECT ) + LoadKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk ) : LoadPNode(c,mem,adr,at,tk) {} virtual int Opcode() const; virtual const Type *Value( PhaseTransform *phase ) const; virtual Node *Identity( PhaseTransform *phase ); virtual bool depends_only_on_test() const { return true; } + + // Polymorphic factory method: + static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, + const TypeKlassPtr *tk = TypeKlassPtr::OBJECT ); }; +//------------------------------LoadNKlassNode--------------------------------- +// Load a narrow Klass from an object. +class LoadNKlassNode : public LoadNNode { +public: + LoadNKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeNarrowOop *tk ) + : LoadNNode(c,mem,adr,at,tk) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegN; } + virtual int store_Opcode() const { return Op_StoreN; } + virtual BasicType memory_type() const { return T_NARROWOOP; } + + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual bool depends_only_on_test() const { return true; } +}; + + //------------------------------LoadSNode-------------------------------------- // Load a short (16bits signed) from memory class LoadSNode : public LoadNode { @@ -696,6 +725,18 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; +//------------------------------AryEq--------------------------------------- +class AryEqNode: public Node { +public: + AryEqNode(Node *control, Node* s1, Node* s2): Node(control, s1, s2) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::BOOL; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + //------------------------------MemBar----------------------------------------- // There are different flavors of Memory Barriers to match the Java Memory // Model. Monitor-enter and volatile-load act as Aquires: no following ref diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/node.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1039,76 +1039,125 @@ //--------------------------dominates------------------------------------------ // Helper function for MemNode::all_controls_dominate(). // Check if 'this' control node dominates or equal to 'sub' control node. +// We already know that if any path back to Root or Start reaches 'this', +// then all paths so, so this is a simple search for one example, +// not an exhaustive search for a counterexample. bool Node::dominates(Node* sub, Node_List &nlist) { assert(this->is_CFG(), "expecting control"); assert(sub != NULL && sub->is_CFG(), "expecting control"); + // detect dead cycle without regions + int iterations_without_region_limit = DominatorSearchLimit; + Node* orig_sub = sub; + Node* dom = this; + bool met_dom = false; nlist.clear(); - bool this_dominates = false; - uint region_input = 0; - while (sub != NULL) { // walk 'sub' up the chain to 'this' - if (sub == this) { + + // Walk 'sub' backward up the chain to 'dom', watching for regions. + // After seeing 'dom', continue up to Root or Start. + // If we hit a region (backward split point), it may be a loop head. + // Keep going through one of the region's inputs. If we reach the + // same region again, go through a different input. Eventually we + // will either exit through the loop head, or give up. + // (If we get confused, break out and return a conservative 'false'.) + while (sub != NULL) { + if (sub->is_top()) break; // Conservative answer for dead code. + if (sub == dom) { if (nlist.size() == 0) { // No Region nodes except loops were visited before and the EntryControl // path was taken for loops: it did not walk in a cycle. return true; - } else if (!this_dominates) { + } else if (met_dom) { + break; // already met before: walk in a cycle + } else { // Region nodes were visited. Continue walk up to Start or Root // to make sure that it did not walk in a cycle. - this_dominates = true; // first time meet - } else { - return false; // already met before: walk in a cycle - } + met_dom = true; // first time meet + iterations_without_region_limit = DominatorSearchLimit; // Reset + } + } + if (sub->is_Start() || sub->is_Root()) { + // Success if we met 'dom' along a path to Start or Root. + // We assume there are no alternative paths that avoid 'dom'. + // (This assumption is up to the caller to ensure!) + return met_dom; } - if (sub->is_Start() || sub->is_Root()) - return this_dominates; - - Node* up = sub->find_exact_control(sub->in(0)); - if (up == NULL || up->is_top()) - return false; // Conservative answer for dead code - + Node* up = sub->in(0); + // Normalize simple pass-through regions and projections: + up = sub->find_exact_control(up); + // If sub == up, we found a self-loop. Try to push past it. if (sub == up && sub->is_Loop()) { - up = sub->in(0); // in(LoopNode::EntryControl); + // Take loop entry path on the way up to 'dom'. + up = sub->in(1); // in(LoopNode::EntryControl); + } else if (sub == up && sub->is_Region() && sub->req() != 3) { + // Always take in(1) path on the way up to 'dom' for clone regions + // (with only one input) or regions which merge > 2 paths + // (usually used to merge fast/slow paths). + up = sub->in(1); } else if (sub == up && sub->is_Region()) { - uint i = 1; - if (nlist.size() == 0) { - // No Region nodes (except Loops) were visited before. - // Take first valid path on the way up to 'this'. - } else if (nlist.at(nlist.size() - 1) == sub) { - // This Region node was just visited. Take other path. - i = region_input + 1; - nlist.pop(); - } else { - // Was this Region node visited before? - uint size = nlist.size(); - for (uint j = 0; j < size; j++) { - if (nlist.at(j) == sub) { - return false; // The Region node was visited before. Give up. + // Try both paths for Regions with 2 input paths (it may be a loop head). + // It could give conservative 'false' answer without information + // which region's input is the entry path. + iterations_without_region_limit = DominatorSearchLimit; // Reset + + bool region_was_visited_before = false; + // Was this Region node visited before? + // If so, we have reached it because we accidentally took a + // loop-back edge from 'sub' back into the body of the loop, + // and worked our way up again to the loop header 'sub'. + // So, take the first unexplored path on the way up to 'dom'. + for (int j = nlist.size() - 1; j >= 0; j--) { + intptr_t ni = (intptr_t)nlist.at(j); + Node* visited = (Node*)(ni & ~1); + bool visited_twice_already = ((ni & 1) != 0); + if (visited == sub) { + if (visited_twice_already) { + // Visited 2 paths, but still stuck in loop body. Give up. + return false; } - } - // The Region node was not visited before. - // Take first valid path on the way up to 'this'. - } - for (; i < sub->req(); i++) { - Node* in = sub->in(i); - if (in != NULL && !in->is_top() && in != sub) { + // The Region node was visited before only once. + // (We will repush with the low bit set, below.) + nlist.remove(j); + // We will find a new edge and re-insert. + region_was_visited_before = true; break; } } - if (i < sub->req()) { - nlist.push(sub); - up = sub->in(i); - region_input = i; + + // Find an incoming edge which has not been seen yet; walk through it. + assert(up == sub, ""); + uint skip = region_was_visited_before ? 1 : 0; + for (uint i = 1; i < sub->req(); i++) { + Node* in = sub->in(i); + if (in != NULL && !in->is_top() && in != sub) { + if (skip == 0) { + up = in; + break; + } + --skip; // skip this nontrivial input + } } + + // Set 0 bit to indicate that both paths were taken. + nlist.push((Node*)((intptr_t)sub + (region_was_visited_before ? 1 : 0))); } - if (sub == up) - return false; // some kind of tight cycle - if (orig_sub == up) - return false; // walk in a cycle + if (up == sub) { + break; // some kind of tight cycle + } + if (up == orig_sub && met_dom) { + // returned back after visiting 'dom' + break; // some kind of cycle + } + if (--iterations_without_region_limit < 0) { + break; // dead cycle + } sub = up; } + + // Did not meet Root or Start node in pred. chain. + // Conservative answer for dead code. return false; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/node.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -53,6 +53,8 @@ class ConNode; class CountedLoopNode; class CountedLoopEndNode; +class DecodeNNode; +class EncodePNode; class FastLockNode; class FastUnlockNode; class IfNode; @@ -438,6 +440,12 @@ public: // Globally replace this node by a given new node, updating all uses. void replace_by(Node* new_node); + // Globally replace this node by a given new node, updating all uses + // and cutting input edges of old node. + void subsume_by(Node* new_node) { + replace_by(new_node); + disconnect_inputs(NULL); + } void set_req_X( uint i, Node *n, PhaseIterGVN *igvn ); // Find the one non-null required input. RegionNode only Node *nonnull_req() const; @@ -577,6 +585,8 @@ DEFINE_CLASS_ID(CheckCastPP, Type, 2) DEFINE_CLASS_ID(CMove, Type, 3) DEFINE_CLASS_ID(SafePointScalarObject, Type, 4) + DEFINE_CLASS_ID(DecodeN, Type, 5) + DEFINE_CLASS_ID(EncodeP, Type, 6) DEFINE_CLASS_ID(Mem, Node, 6) DEFINE_CLASS_ID(Load, Mem, 0) @@ -685,6 +695,8 @@ DEFINE_CLASS_QUERY(Cmp) DEFINE_CLASS_QUERY(CountedLoop) DEFINE_CLASS_QUERY(CountedLoopEnd) + DEFINE_CLASS_QUERY(DecodeN) + DEFINE_CLASS_QUERY(EncodeP) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) DEFINE_CLASS_QUERY(If) diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/output.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -48,6 +48,7 @@ // Initialize the space for the BufferBlob used to find and verify // instruction size in MachNode::emit_size() init_scratch_buffer_blob(); + if (failing()) return; // Out of memory // Make sure I can find the Start Node Block_Array& bbs = _cfg->_bbs; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/parse1.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1901,7 +1901,7 @@ // finalization. In general this will fold up since the concrete // class is often visible so the access flags are constant. Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); - Node* klass = _gvn.transform(new (C, 3) LoadKlassNode(NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); + Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) ); Node* access_flags_addr = basic_plus_adr(klass, klass, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc)); Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT); diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/parseHelper.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -38,7 +38,7 @@ // Get method const TypeInstPtr* method_type = TypeInstPtr::make(TypePtr::Constant, method->klass(), true, method, 0); - Node *method_node = _gvn.transform( new (C, 1) ConPNode(method_type) ); + Node *method_node = _gvn.transform( ConNode::make(C, method_type) ); kill_dead_locals(); @@ -143,7 +143,7 @@ int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset - Node* array_klass = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeInstPtr::KLASS)); + Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) ); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); @@ -189,7 +189,7 @@ // Extract the array element class int element_klass_offset = objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); - Node *a_e_klass = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p2, tak)); + Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) ); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/type.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -311,8 +311,18 @@ mreg2type[Op_RegFlags] = TypeInt::CC; TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), current->env()->Object_klass(), false, arrayOopDesc::length_offset_in_bytes()); - // There is no shared klass for Object[]. See note in TypeAryPtr::klass(). - TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); + + TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); + +#ifdef _LP64 + if (UseCompressedOops) { + TypeAryPtr::OOPS = TypeAryPtr::NARROWOOPS; + } else +#endif + { + // There is no shared klass for Object[]. See note in TypeAryPtr::klass(). + TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); + } TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, Type::OffsetBot); TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT), true, Type::OffsetBot); TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, Type::OffsetBot); @@ -321,9 +331,10 @@ TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT), true, Type::OffsetBot); TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true, Type::OffsetBot); - TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL; // what should this be? + // Nobody should ask _array_body_type[T_NARROWOOP]. Use NULL as assert. + TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL; TypeAryPtr::_array_body_type[T_OBJECT] = TypeAryPtr::OOPS; - TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays + TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays TypeAryPtr::_array_body_type[T_BYTE] = TypeAryPtr::BYTES; TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES; // boolean[] is a byte array TypeAryPtr::_array_body_type[T_SHORT] = TypeAryPtr::SHORTS; @@ -696,7 +707,7 @@ ResourceMark rm; Dict d(cmpkey,hashkey); // Stop recursive type dumping dump2(d,1, st); - if (isa_ptr() && is_ptr()->is_narrow()) { + if (is_ptr_to_narrowoop()) { st->print(" [narrow]"); } } @@ -929,6 +940,7 @@ case InstPtr: case KlassPtr: case AryPtr: + case NarrowOop: case Int: case Long: case FloatTop: @@ -1075,6 +1087,7 @@ case InstPtr: case KlassPtr: case AryPtr: + case NarrowOop: case Long: case FloatTop: case FloatCon: @@ -1082,7 +1095,6 @@ case DoubleTop: case DoubleCon: case DoubleBot: - case NarrowOop: case Bottom: // Ye Olde Default return Type::BOTTOM; default: // All else is a mistake @@ -1317,6 +1329,7 @@ case InstPtr: case KlassPtr: case AryPtr: + case NarrowOop: case Int: case FloatTop: case FloatCon: @@ -2146,6 +2159,67 @@ // Convenience common pre-built type. const TypeOopPtr *TypeOopPtr::BOTTOM; +//------------------------------TypeOopPtr------------------------------------- +TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ) + : TypePtr(t, ptr, offset), + _const_oop(o), _klass(k), + _klass_is_exact(xk), + _is_ptr_to_narrowoop(false), + _instance_id(instance_id) { +#ifdef _LP64 + if (UseCompressedOops && _offset != 0) { + if (klass() == NULL) { + assert(this->isa_aryptr(), "only arrays without klass"); + _is_ptr_to_narrowoop = true; + } else if (_offset == oopDesc::klass_offset_in_bytes()) { + _is_ptr_to_narrowoop = true; + } else if (this->isa_aryptr()) { + _is_ptr_to_narrowoop = (klass()->is_obj_array_klass() && + _offset != arrayOopDesc::length_offset_in_bytes()); + } else if (klass() == ciEnv::current()->Class_klass() && + (_offset == java_lang_Class::klass_offset_in_bytes() || + _offset == java_lang_Class::array_klass_offset_in_bytes())) { + // Special hidden fields from the Class. + assert(this->isa_instptr(), "must be an instance ptr."); + _is_ptr_to_narrowoop = true; + } else if (klass()->is_instance_klass()) { + ciInstanceKlass* ik = klass()->as_instance_klass(); + ciField* field = NULL; + if (this->isa_klassptr()) { + // Perm objects don't use compressed references, except for + // static fields which are currently compressed. + field = ik->get_field_by_offset(_offset, true); + if (field != NULL) { + BasicType basic_elem_type = field->layout_type(); + _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || + basic_elem_type == T_ARRAY); + } + } else if (_offset == OffsetBot || _offset == OffsetTop) { + // unsafe access + _is_ptr_to_narrowoop = true; + } else { // exclude unsafe ops + assert(this->isa_instptr(), "must be an instance ptr."); + // Field which contains a compressed oop references. + field = ik->get_field_by_offset(_offset, false); + if (field != NULL) { + BasicType basic_elem_type = field->layout_type(); + _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || + basic_elem_type == T_ARRAY); + } else if (klass()->equals(ciEnv::current()->Object_klass())) { + // Compile::find_alias_type() cast exactness on all types to verify + // that it does not affect alias type. + _is_ptr_to_narrowoop = true; + } else { + // Type for the copy start in LibraryCallKit::inline_native_clone(). + assert(!klass_is_exact(), "only non-exact klass"); + _is_ptr_to_narrowoop = true; + } + } + } + } +#endif +} + //------------------------------make------------------------------------------- const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset) { @@ -2593,9 +2667,13 @@ //-----------------------------cast_to_instance------------------------------- const TypeOopPtr *TypeInstPtr::cast_to_instance(int instance_id) const { if( instance_id == _instance_id) return this; - bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true; - - return make(ptr(), klass(), exact, const_oop(), _offset, instance_id); + bool exact = true; + PTR ptr_t = NotNull; + if (instance_id == UNKNOWN_INSTANCE) { + exact = _klass_is_exact; + ptr_t = _ptr; + } + return make(ptr_t, klass(), exact, const_oop(), _offset, instance_id); } //------------------------------xmeet_unloaded--------------------------------- @@ -3014,6 +3092,7 @@ // Convenience common pre-built types. const TypeAryPtr *TypeAryPtr::RANGE; const TypeAryPtr *TypeAryPtr::OOPS; +const TypeAryPtr *TypeAryPtr::NARROWOOPS; const TypeAryPtr *TypeAryPtr::BYTES; const TypeAryPtr *TypeAryPtr::SHORTS; const TypeAryPtr *TypeAryPtr::CHARS; @@ -3063,8 +3142,13 @@ //-----------------------------cast_to_instance------------------------------- const TypeOopPtr *TypeAryPtr::cast_to_instance(int instance_id) const { if( instance_id == _instance_id) return this; - bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true; - return make(ptr(), const_oop(), _ary, klass(), exact, _offset, instance_id); + bool exact = true; + PTR ptr_t = NotNull; + if (instance_id == UNKNOWN_INSTANCE) { + exact = _klass_is_exact; + ptr_t = _ptr; + } + return make(ptr_t, const_oop(), _ary, klass(), exact, _offset, instance_id); } //-----------------------------narrow_size_type------------------------------- @@ -3547,7 +3631,7 @@ k_ary = ciTypeArrayKlass::make(el->basic_type()); } - if( this != TypeAryPtr::OOPS ) + if( this != TypeAryPtr::OOPS ) { // The _klass field acts as a cache of the underlying // ciKlass for this array type. In order to set the field, // we need to cast away const-ness. @@ -3562,6 +3646,11 @@ // a bit less efficient than caching, but calls to // TypeAryPtr::OOPS->klass() are not common enough to matter. ((TypeAryPtr*)this)->_klass = k_ary; + if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() && + _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes()) { + ((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true; + } + } return k_ary; } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/opto/type.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -191,9 +191,8 @@ virtual const Type *filter( const Type *kills ) const; // Returns true if this pointer points at memory which contains a - // compressed oop references. In 32-bit builds it's non-virtual - // since we don't support compressed oops at all in the mode. - LP64_ONLY(virtual) bool is_narrow() const { return false; } + // compressed oop references. + bool is_ptr_to_narrowoop() const; // Convenience access float getf() const; @@ -213,8 +212,8 @@ const TypePtr *isa_ptr() const; // Returns NULL if not ptr type const TypeRawPtr *isa_rawptr() const; // NOT Java oop const TypeRawPtr *is_rawptr() const; // Asserts is rawptr - const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer - const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type + const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer + const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type const TypeOopPtr *isa_oopptr() const; // Returns NULL if not oop ptr type const TypeOopPtr *is_oopptr() const; // Java-style GC'd pointer const TypeKlassPtr *isa_klassptr() const; // Returns NULL if not KlassPtr @@ -643,7 +642,7 @@ // Some kind of oop (Java pointer), either klass or instance or array. class TypeOopPtr : public TypePtr { protected: - TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ) : TypePtr(t, ptr, offset), _const_oop(o), _klass(k), _klass_is_exact(xk), _instance_id(instance_id) { } + TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ); public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -660,8 +659,9 @@ ciKlass* _klass; // Klass object // Does the type exclude subclasses of the klass? (Inexact == polymorphic.) bool _klass_is_exact; + bool _is_ptr_to_narrowoop; - int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance + int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance // of this type which is distinct. This is the the node index of the // node creating this instance @@ -696,6 +696,11 @@ ciObject* const_oop() const { return _const_oop; } virtual ciKlass* klass() const { return _klass; } bool klass_is_exact() const { return _klass_is_exact; } + + // Returns true if this pointer points at memory which contains a + // compressed oop references. + bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; } + bool is_instance() const { return _instance_id != UNKNOWN_INSTANCE; } uint instance_id() const { return _instance_id; } bool is_instance_field() const { return _instance_id != UNKNOWN_INSTANCE && _offset >= 0; } @@ -716,12 +721,6 @@ // returns the equivalent compressed version of this pointer type virtual const TypeNarrowOop* make_narrowoop() const; -#ifdef _LP64 - virtual bool is_narrow() const { - return (UseCompressedOops && _offset != 0); - } -#endif - virtual const Type *xmeet( const Type *t ) const; virtual const Type *xdual() const; // Compute dual right now. @@ -843,15 +842,10 @@ virtual const Type *xmeet( const Type *t ) const; virtual const Type *xdual() const; // Compute dual right now. -#ifdef _LP64 - virtual bool is_narrow() const { - return (UseCompressedOops && klass() != NULL && _offset != 0); - } -#endif - // Convenience common pre-built types. static const TypeAryPtr *RANGE; static const TypeAryPtr *OOPS; + static const TypeAryPtr *NARROWOOPS; static const TypeAryPtr *BYTES; static const TypeAryPtr *SHORTS; static const TypeAryPtr *CHARS; @@ -901,18 +895,6 @@ virtual const Type *xmeet( const Type *t ) const; virtual const Type *xdual() const; // Compute dual right now. -#ifdef _LP64 - // Perm objects don't use compressed references, except for static fields - // which are currently compressed - virtual bool is_narrow() const { - if (UseCompressedOops && _offset != 0 && _klass->is_instance_klass()) { - ciInstanceKlass* ik = _klass->as_instance_klass(); - return ik != NULL && ik->get_field_by_offset(_offset, true) != NULL; - } - return false; - } -#endif - // Convenience common pre-built types. static const TypeKlassPtr* OBJECT; // Not-null object klass or below static const TypeKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same @@ -921,7 +903,7 @@ #endif }; -//------------------------------TypeNarrowOop---------------------------------------- +//------------------------------TypeNarrowOop---------------------------------- // A compressed reference to some kind of Oop. This type wraps around // a preexisting TypeOopPtr and forwards most of it's operations to // the underlying type. It's only real purpose is to track the @@ -1013,6 +995,14 @@ }; //------------------------------accessors-------------------------------------- +inline bool Type::is_ptr_to_narrowoop() const { +#ifdef _LP64 + return (isa_oopptr() != NULL && is_oopptr()->is_ptr_to_narrowoop_nv()); +#else + return false; +#endif +} + inline float Type::getf() const { assert( _base == FloatCon, "Not a FloatCon" ); return ((TypeF*)this)->_f; diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/runtime/arguments.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -1174,9 +1174,11 @@ // field offset to determine free list chunk markers. // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. - if (!UseConcMarkSweepGC && MaxHeapSize <= max_heap_for_compressed_oops()) { + if (MaxHeapSize <= max_heap_for_compressed_oops()) { if (FLAG_IS_DEFAULT(UseCompressedOops)) { - FLAG_SET_ERGO(bool, UseCompressedOops, true); + // Leave compressed oops off by default. Uncomment + // the following line to return it to default status. + // FLAG_SET_ERGO(bool, UseCompressedOops, true); } } else { if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { @@ -1312,6 +1314,9 @@ if (AggressiveOpts && FLAG_IS_DEFAULT(DoEscapeAnalysis)) { FLAG_SET_DEFAULT(DoEscapeAnalysis, true); } + if (AggressiveOpts && FLAG_IS_DEFAULT(SpecialArraysEquals)) { + FLAG_SET_DEFAULT(SpecialArraysEquals, true); + } #endif if (AggressiveOpts) { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/runtime/globals.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -291,6 +291,9 @@ "Use 32-bit object references in 64-bit VM. " \ "lp64_product means flag is always constant in 32 bit VM") \ \ + lp64_product(bool, CheckCompressedOops, trueInDebug, \ + "generate checks in encoding/decoding code") \ + \ /* UseMembar is theoretically a temp flag used for memory barrier \ * removal testing. It was supposed to be removed before FCS but has \ * been re-added (see 6401008) */ \ @@ -457,6 +460,9 @@ develop(bool, SpecialStringIndexOf, true, \ "special version of string indexOf") \ \ + product(bool, SpecialArraysEquals, false, \ + "special version of Arrays.equals(char[],char[])") \ + \ develop(bool, TraceCallFixup, false, \ "traces all call fixups") \ \ @@ -2240,6 +2246,9 @@ product(bool, AggressiveOpts, false, \ "Enable aggressive optimizations - see arguments.cpp") \ \ + product(bool, UseStringCache, false, \ + "Enable String cache capabilities on String.java") \ + \ /* statistics */ \ develop(bool, UseVTune, false, \ "enable support for Intel's VTune profiler") \ diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/runtime/java.hpp --- a/src/share/vm/runtime/java.hpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/runtime/java.hpp Tue Jun 17 15:27:05 2008 -0700 @@ -68,8 +68,24 @@ static bool is_jdk13x_version() { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 3; } static bool is_jdk14x_version() { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 4; } static bool is_jdk15x_version() { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 5; } - static bool is_jdk16x_version() { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 6; } - static bool is_jdk17x_version() { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 7; } + + static bool is_jdk16x_version() { + if (is_jdk_version_initialized()) { + return _jdk_version == 6; + } else { + assert(is_pre_jdk16_version(), "must have been initialized"); + return false; + } + } + + static bool is_jdk17x_version() { + if (is_jdk_version_initialized()) { + return _jdk_version == 7; + } else { + assert(is_pre_jdk16_version(), "must have been initialized"); + return false; + } + } static bool supports_thread_park_blocker() { return _version_info.thread_park_blocker; } @@ -85,14 +101,22 @@ } static bool is_gte_jdk16x_version() { // Keep the semantics of this that the version number is >= 1.6 - assert(is_jdk_version_initialized(), "Not initialized"); - return _jdk_version >= 6; + if (is_jdk_version_initialized()) { + return _jdk_version >= 6; + } else { + assert(is_pre_jdk16_version(), "Not initialized"); + return false; + } } static bool is_gte_jdk17x_version() { // Keep the semantics of this that the version number is >= 1.7 - assert(is_jdk_version_initialized(), "Not initialized"); - return _jdk_version >= 7; + if (is_jdk_version_initialized()) { + return _jdk_version >= 7; + } else { + assert(is_pre_jdk16_version(), "Not initialized"); + return false; + } } static bool is_jdk_version_initialized() { diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/runtime/thread.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -2926,21 +2926,42 @@ } if (AggressiveOpts) { - // Forcibly initialize java/util/HashMap and mutate the private - // static final "frontCacheEnabled" field before we start creating instances + { + // Forcibly initialize java/util/HashMap and mutate the private + // static final "frontCacheEnabled" field before we start creating instances #ifdef ASSERT - klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); - assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet"); + klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet"); #endif - klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); - KlassHandle k = KlassHandle(THREAD, k_o); - guarantee(k.not_null(), "Must find java/util/HashMap"); - instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); - ik->initialize(CHECK_0); - fieldDescriptor fd; - // Possible we might not find this field; if so, don't break - if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + KlassHandle k = KlassHandle(THREAD, k_o); + guarantee(k.not_null(), "Must find java/util/HashMap"); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field; if so, don't break + if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } + } + + if (UseStringCache) { + // Forcibly initialize java/lang/String and mutate the private + // static final "stringCacheEnabled" field before we start creating instances +#ifdef ASSERT + klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_lang_String(), Handle(), Handle(), CHECK_0); + assert(tmp_k == NULL, "java/lang/String should not be loaded yet"); +#endif + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_String(), Handle(), Handle(), CHECK_0); + KlassHandle k = KlassHandle(THREAD, k_o); + guarantee(k.not_null(), "Must find java/lang/String"); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field; if so, don't break + if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } } } diff -r abe7181cbe8a -r 4f91c08b3e44 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Tue Jun 10 10:22:49 2008 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Tue Jun 17 15:27:05 2008 -0700 @@ -894,6 +894,7 @@ /*******************************************************************/ \ \ declare_unsigned_integer_type(size_t) \ + declare_integer_type(ssize_t) \ declare_unsigned_integer_type(const size_t) \ declare_integer_type(intx) \ declare_integer_type(intptr_t) \ @@ -1694,7 +1695,12 @@ declare_constant(markOopDesc::no_hash) \ declare_constant(markOopDesc::no_hash_in_place) \ declare_constant(markOopDesc::no_lock_in_place) \ - declare_constant(markOopDesc::max_age) + declare_constant(markOopDesc::max_age) \ + \ + /* Constants in markOop used by CMS. */ \ + declare_constant(markOopDesc::cms_shift) \ + declare_constant(markOopDesc::cms_mask) \ + declare_constant(markOopDesc::size_shift) \ /* NOTE that we do not use the last_entry() macro here; it is used */ /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and */ @@ -1958,6 +1964,7 @@ GENERATE_STATIC_VM_STRUCT_ENTRY) VM_STRUCTS_CMS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ GENERATE_STATIC_VM_STRUCT_ENTRY) #endif // SERIALGC @@ -2099,6 +2106,7 @@ CHECK_STATIC_VM_STRUCT_ENTRY); VM_STRUCTS_CMS(CHECK_NONSTATIC_VM_STRUCT_ENTRY, + CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); #endif // SERIALGC @@ -2203,6 +2211,7 @@ debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, \ ENSURE_FIELD_TYPE_PRESENT)); debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, \ + ENSURE_FIELD_TYPE_PRESENT, \ ENSURE_FIELD_TYPE_PRESENT)); #endif // SERIALGC debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, \ diff -r abe7181cbe8a -r 4f91c08b3e44 test/compiler/6659207/Test.java --- a/test/compiler/6659207/Test.java Tue Jun 10 10:22:49 2008 -0700 +++ b/test/compiler/6659207/Test.java Tue Jun 17 15:27:05 2008 -0700 @@ -1,23 +1,24 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * + * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * - * - * - * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * - * - * - * - * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). * - * - * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * - * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * */ diff -r abe7181cbe8a -r 4f91c08b3e44 test/compiler/6661247/Test.java --- a/test/compiler/6661247/Test.java Tue Jun 10 10:22:49 2008 -0700 +++ b/test/compiler/6661247/Test.java Tue Jun 17 15:27:05 2008 -0700 @@ -1,23 +1,24 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * + * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * - * - * - * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * - * - * - * - * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). * - * - * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * - * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * */ diff -r abe7181cbe8a -r 4f91c08b3e44 test/compiler/6663621/IVTest.java --- a/test/compiler/6663621/IVTest.java Tue Jun 10 10:22:49 2008 -0700 +++ b/test/compiler/6663621/IVTest.java Tue Jun 17 15:27:05 2008 -0700 @@ -1,23 +1,24 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * + * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * - * - * - * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * - * - * - * - * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). * - * - * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * - * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * */ diff -r abe7181cbe8a -r 4f91c08b3e44 test/compiler/6689060/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6689060/Test.java Tue Jun 17 15:27:05 2008 -0700 @@ -0,0 +1,577 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * @test + * @bug 6689060 + * @summary Escape Analysis does not work with Compressed Oops + * @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.dummy -XX:+AggressiveOpts Test + */ + +import java.lang.reflect.Array; + +class Point { + int x; + int y; + Point next; + int ax[]; + int ay[]; + Point pax[]; + Point pay[]; + public Point getNext() { + return next; + } +} + +public class Test { + + void dummy() { + // Empty method to verify correctness of DebugInfo. + // Use -XX:CompileCommand=exclude,Test.dummy + } + + int ival(int i) { + return i*2; + } + + int test80(int y, int l, int i) { + Point p = new Point(); + p.ax = new int[2]; + p.ay = new int[2]; + int x = 3; + p.ax[0] = x; + p.ay[1] = 3 * x + y; + dummy(); + return p.ax[0] * p.ay[1]; + } + + int test81(int y, int l, int i) { + Point p = new Point(); + p.ax = new int[2]; + p.ay = new int[2]; + int x = 3; + p.ax[0] = x; + p.ay[1] = 3 * x + y; + dummy(); + return p.ax[0] * p.ay[1]; + } + + + int test44(int y) { + Point p1 = new Point(); + p1.x = ival(3); + dummy(); + p1.y = 3 * p1.x + y; + return p1.y; + } + + int test43(int y) { + Point p1 = new Point(); + if ( (y & 1) == 1 ) { + p1.x = ival(3); + } else { + p1.x = ival(5); + } + dummy(); + p1.y = 3 * p1.x + y; + return p1.y; + } + + int test42(int y) { + Point p1 = new Point(); + p1.x = 3; + for (int i = 0; i < y; i++) { + if ( (i & 1) == 1 ) { + p1.x += 4; + } + } + p1.y = 3 * y + p1.x; + return p1.y; + } + + int test40(int y) { + Point p1 = new Point(); + if ( (y & 1) == 1 ) { + p1.x = 3; + } else { + p1.x = 5; + } + p1.y = 3 * p1.x + y; + return p1.y; + } + + int test41(int y) { + Point p1 = new Point(); + if ( (y & 1) == 1 ) { + p1.x += 4; + } else { + p1.x += 5; + } + p1.y = 3 * p1.x + y; + return p1.y; + } + + Point test00(int y) { + int x = 3; + Point p = new Point(); + p.x = x; + p.y = 3 * x + y; + return p; + } + + Point test01(int y) { + int x = 3; + Point p = new Point(); + p.x = x; + p.y = 3 * x + y; + dummy(); + return p; + } + + Point test02(int y) { + int x = 3; + Point p1 = null; + for (int i = 0; i < y; i++) { + Point p2 = new Point(); + p2.x = x; + p2.y = 3 * y + x; + p2.next = p1; + p1 = p2; + } + return p1; + } + + Point test03(int y) { + int x = 3; + Point p1 = null; + for (int i = 0; i < y; i++) { + Point p2 = new Point(); + p2.x = x; + p2.y = 3 * y + x; + p2.next = p1; + p1 = p2; + } + dummy(); + return p1; + } + + Point test04(int y) { + int x = 3; + Point p1 = null; + for (int i = 0; i < y; i++) { + Point p2 = new Point(); + p2.x = x; + p2.y = 3 * y + x; + p2.next = p1; + dummy(); + p1 = p2; + } + return p1; + } + + int test05(int y) { + int x = 3; + Point p1 = new Point(); + for (int i = 0; i < y; i++) { + Point p2 = new Point(); + p2.x = x; + p2.y = 3 * y + x; + p1.next = p2; + p1 = p2; + } + return p1.y; + } + + int test0(int y) { + int x = 3; + Point p = new Point(); + p.x = x; + p.y = 3 * x + y; + dummy(); + return p.x * p.y; + } + + int test1(int y) { + Point p = new Point(); + if ( (y & 1) == 1 ) { + p = new Point(); // Kill previous + } + int x = 3; + p.x = x; + p.y = 3 * x + y; + dummy(); + return p.x * p.y; + } + + int test2(int y) { + Point p1 = new Point(); + Point p2 = new Point(); + p1.x = 3; + p2.x = 4; + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test3(int y, Point p1) { + Point p2 = new Point(); + p1.x = 3; + p2.x = 4; + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test4(int y) { + Point p1 = new Point(); + Point p2 = new Point(); + if ( (y & 1) == 1 ) { + p1.x = 3; + p2.x = 4; + } else { + p1.x = 5; + p2.x = 6; + } + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test5(int y, Point p1) { + Point p2 = new Point(); + if ( (y & 1) == 1 ) { + p1.x = 3; + p2.x = 4; + } else { + p1.x = 5; + p2.x = 6; + } + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test6(int y) { + Point p1 = new Point(); + Point p2 = new Point(); + p1.next = p2; + if ( (y & 1) == 1 ) { + p1.x = 3; + p1.getNext().x = 4; + } else { + p1.x = 5; + p1.getNext().x = 6; + } + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test7(int y, Point p1) { + Point p2 = new Point(); + p1.next = p2; + if ( (y & 1) == 1 ) { + p1.x = 3; + p1.getNext().x = 4; + } else { + p1.x = 5; + p1.getNext().x = 6; + } + p1.y = 3 * p2.x + y; + p2.y = 3 * p1.x + y; + dummy(); + return p1.y * p2.y; + } + + int test8(int y, int l, int i) { + Point p = new Point(); + p.ax = new int[l]; + p.ay = new int[l]; + int x = 3; + p.ax[i] = x; + p.ay[i] = 3 * x + y; + dummy(); + return p.ax[i] * p.ay[i]; + } + + int test9(int y, int l, int i) { + Point p = new Point(); + p.pax = new Point[l]; + p.pay = new Point[l]; + p.pax[i] = new Point(); + p.pay[i] = new Point(); + p.pax[i].x = 3; + p.pay[i].x = 4; + p.pax[i].y = 3 * p.pay[i].x + y; + p.pay[i].y = 3 * p.pax[i].x + y; + dummy(); + return p.pax[i].y * p.pay[i].y; + } + + int test10(int y, int l, int i, Class cls) { + Point p = new Point(); + try { + p.pax = (Point[])Array.newInstance(cls, l); + p.pax[i] = (Point)cls.newInstance(); + } + catch(java.lang.InstantiationException ex) { + return 0; + } + catch(java.lang.IllegalAccessException ex) { + return 0; + } + p.pax[i].x = 3; + p.pax[i].y = 3 * p.pax[i].x + y; + dummy(); + return p.pax[i].x * p.pax[i].y; + } + + int test11(int y) { + Point p1 = new Point(); + Point p2 = new Point(); + p1.next = p2; + if ( (y & 1) == 1 ) { + p1.x = 3; + p1.next.x = 4; + } else { + p1.x = 5; + p1.next.x = 6; + } + p1.y = 3 * p1.next.x + y; + p1.next.y = 3 * p1.x + y; + dummy(); + return p1.y * p1.next.y; + } + + int test12(int y) { + Point p1 = new Point(); + p1.next = p1; + if ( (y & 1) == 1 ) { + p1.x = 3; + p1.next.x = 4; + } else { + p1.x = 5; + p1.next.x = 6; + } + p1.y = 3 * p1.next.x + y; + p1.next.y = 3 * p1.x + y; + dummy(); + return p1.y * p1.next.y; + } + + + public static void main(String args[]) { + Test tsr = new Test(); + Point p = new Point(); + Point ptmp = p; + Class cls = Point.class; + int y = 0; + for (int i=0; i<10000; i++) { + ptmp.next = tsr.test00(1); + ptmp.next = tsr.test01(1); + ptmp.next = tsr.test02(1); + ptmp.next = tsr.test03(1); + ptmp.next = tsr.test04(1); + + y = tsr.test05(1); + + y = tsr.test80(y, 1, 0); + y = tsr.test81(y, 1, 0); + + y = tsr.test44(y); + y = tsr.test43(y); + y = tsr.test42(y); + y = tsr.test40(y); + y = tsr.test41(y); + + y = tsr.test0(y); + y = tsr.test1(y); + y = tsr.test2(y); + y = tsr.test3(y, p); + y = tsr.test4(y); + y = tsr.test5(y, p); + y = tsr.test6(y); + y = tsr.test7(y, p); + y = tsr.test8(y, 1, 0); + y = tsr.test9(y, 1, 0); + y = tsr.test10(y, 1, 0, cls); + y = tsr.test11(y); + y = tsr.test12(y); + } + for (int i=0; i<10000; i++) { + ptmp.next = tsr.test00(1); + ptmp.next = tsr.test01(1); + ptmp.next = tsr.test02(1); + ptmp.next = tsr.test03(1); + ptmp.next = tsr.test04(1); + + y = tsr.test05(1); + + y = tsr.test80(y, 1, 0); + y = tsr.test81(y, 1, 0); + + y = tsr.test44(y); + y = tsr.test43(y); + y = tsr.test42(y); + y = tsr.test40(y); + y = tsr.test41(y); + + y = tsr.test0(y); + y = tsr.test1(y); + y = tsr.test2(y); + y = tsr.test3(y, p); + y = tsr.test4(y); + y = tsr.test5(y, p); + y = tsr.test6(y); + y = tsr.test7(y, p); + y = tsr.test8(y, 1, 0); + y = tsr.test9(y, 1, 0); + y = tsr.test10(y, 1, 0, cls); + y = tsr.test11(y); + y = tsr.test12(y); + } + for (int i=0; i<10000; i++) { + ptmp.next = tsr.test00(1); + ptmp.next = tsr.test01(1); + ptmp.next = tsr.test02(1); + ptmp.next = tsr.test03(1); + ptmp.next = tsr.test04(1); + + y = tsr.test05(1); + + y = tsr.test80(y, 1, 0); + y = tsr.test81(y, 1, 0); + + y = tsr.test44(y); + y = tsr.test43(y); + y = tsr.test42(y); + y = tsr.test40(y); + y = tsr.test41(y); + + y = tsr.test0(y); + y = tsr.test1(y); + y = tsr.test2(y); + y = tsr.test3(y, p); + y = tsr.test4(y); + y = tsr.test5(y, p); + y = tsr.test6(y); + y = tsr.test7(y, p); + y = tsr.test8(y, 1, 0); + y = tsr.test9(y, 1, 0); + y = tsr.test10(y, 1, 0, cls); + y = tsr.test11(y); + y = tsr.test12(y); + } + + int z = 0; + y = tsr.test80(0, 1, 0); + z += y; + System.out.println("After 'test80' y=" + y); + y = tsr.test81(0, 1, 0); + z += y; + System.out.println("After 'test81' y=" + y); + + y = tsr.test44(0); + z += y; + System.out.println("After 'test44' y=" + y); + y = tsr.test43(0); + z += y; + System.out.println("After 'test43' y=" + y); + y = tsr.test42(0); + z += y; + System.out.println("After 'test42' y=" + y); + y = tsr.test40(0); + z += y; + System.out.println("After 'test40' y=" + y); + y = tsr.test41(0); + z += y; + System.out.println("After 'test41' y=" + y); + + ptmp.next = tsr.test00(1); + z += y; + System.out.println("After 'test00' p.y=" + ptmp.next.y); + ptmp.next = tsr.test01(1); + z += y; + System.out.println("After 'test01' p.y=" + ptmp.next.y); + ptmp.next = tsr.test02(1); + z += y; + System.out.println("After 'test02' p.y=" + ptmp.next.y); + ptmp.next = tsr.test03(1); + z += y; + System.out.println("After 'test03' p.y=" + ptmp.next.y); + ptmp.next = tsr.test04(1); + z += y; + System.out.println("After 'test04' p.y=" + ptmp.next.y); + + y = tsr.test05(1); + z += y; + System.out.println("After 'test05' y=" + y); + + y = tsr.test0(0); + z += y; + System.out.println("After 'test0' y=" + y); + y = tsr.test1(0); + z += y; + System.out.println("After 'test1' y=" + y); + y = tsr.test2(0); + z += y; + System.out.println("After 'test2' y=" + y); + y = tsr.test3(0, new Point()); + z += y; + System.out.println("After 'test3' y=" + y); + y = tsr.test4(0); + z += y; + System.out.println("After 'test4' y=" + y); + y = tsr.test5(0, new Point()); + z += y; + System.out.println("After 'test5' y=" + y); + y = tsr.test6(0); + z += y; + System.out.println("After 'test6' y=" + y); + y = tsr.test7(0, new Point()); + z += y; + System.out.println("After 'test7' y=" + y); + y = tsr.test8(0, 1, 0); + z += y; + System.out.println("After 'test8' y=" + y); + y = tsr.test9(0, 1, 0); + z += y; + System.out.println("After 'test9' y=" + y); + y = tsr.test10(0, 1, 0, cls); + z += y; + System.out.println("After 'test10' y=" + y); + y = tsr.test11(0); + z += y; + System.out.println("After 'test11' y=" + y); + y = tsr.test12(0); + z += y; + System.out.println("After 'test12' y=" + y); + System.out.println("Sum of y =" + z); + } +} diff -r abe7181cbe8a -r 4f91c08b3e44 test/compiler/6695810/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6695810/Test.java Tue Jun 17 15:27:05 2008 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * @test + * @bug 6695810 + * @summary null oop passed to encode_heap_oop_not_null + * @run main/othervm -Xbatch Test + */ + +public class Test { + Test _t; + + static void test(Test t1, Test t2) { + if (t2 != null) + t1._t = t2; + + if (t2 != null) + t1._t = t2; + } + + public static void main(String[] args) { + Test t = new Test(); + for (int i = 0; i < 50; i++) { + for (int j = 0; j < 100; j++) { + test(t, t); + } + test(t, null); + } + for (int i = 0; i < 10000; i++) { + test(t, t); + } + test(t, null); + } +}