--- a/hotspot/agent/make/Makefile Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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() {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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());
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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<IndexSetSize; i += IndexSetStride) {
+ FreeList freeList = (FreeList) VMObjectFactory.newObject(FreeList.class, cur);
+ size += i*freeList.count();
+ cur= cur.addOffsetTo(IndexSetStride*FreeList.sizeOf());
+ }
+
+ // large block
+ BinaryTreeDictionary bfbd = (BinaryTreeDictionary) VMObjectFactory.newObject(BinaryTreeDictionary.class,
+ dictionaryField.getValue(addr));
+ size += bfbd.size();
+
+
+ // linear block in TLAB
+ LinearAllocBlock lab = (LinearAllocBlock) VMObjectFactory.newObject(LinearAllocBlock.class,
+ addr.addOffsetTo(smallLinearAllocBlockFieldOffset));
+ size += lab.word_size();
+
+ return size*heapWordSize;
+ }
public void printOn(PrintStream tty) {
tty.print("free-list-space");
+ tty.print("[ " + bottom() + " , " + end() + " ) ");
+ long cap = capacity();
+ long used_size = used();
+ long free_size = free();
+ int used_perc = (int)((double)used_size/cap*100);
+ tty.print("space capacity = " + cap + " used(" + used_perc + "%)= " + used_size + " ");
+ tty.print("free= " + free_size );
+ tty.print("\n");
+
}
public Address skipBlockSizeUsingPrintezisBits(Address pos) {
@@ -121,7 +189,7 @@
cur = cur.addOffsetTo(adjustObjectSizeInBytes(size));
}
- if (FreeChunk.secondWordIndicatesFreeChunk(dbg.getAddressValue(klassOop))) {
+ if (FreeChunk.indicatesFreeChunk(cur)) {
if (! cur.equals(regionStart)) {
res.add(new MemRegion(regionStart, cur));
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DefNewGeneration.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DefNewGeneration.java Tue Jun 17 15:27:05 2008 -0700
@@ -96,9 +96,9 @@
public void printOn(PrintStream tty) {
tty.print(" eden");
eden().printOn(tty);
- tty.print(" from");
+ tty.print("\n from");
from().printOn(tty);
- tty.print(" to ");
+ tty.print("\n to ");
to().printOn(tty);
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Tue Jun 17 15:27:05 2008 -0700
@@ -28,6 +28,7 @@
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.oops.*;
public class FreeChunk extends VMObject {
static {
@@ -42,13 +43,13 @@
Type type = db.lookupType("FreeChunk");
nextField = type.getAddressField("_next");
prevField = type.getAddressField("_prev");
- sizeField = type.getCIntegerField("_size");
+ sizeField = type.getAddressField("_size");
}
// Fields
private static AddressField nextField;
private static AddressField prevField;
- private static CIntegerField sizeField;
+ private static AddressField sizeField;
// Accessors
public FreeChunk next() {
@@ -61,20 +62,34 @@
}
public long size() {
- return sizeField.getValue(addr);
+ if (VM.getVM().isCompressedOopsEnabled()) {
+ Mark mark = new Mark(sizeField.getValue(addr));
+ return mark.getSize();
+ } else {
+ Address size = sizeField.getValue(addr);
+ Debugger dbg = VM.getVM().getDebugger();
+ return dbg.getAddressValue(size);
+ }
}
public FreeChunk(Address addr) {
super(addr);
}
- public static boolean secondWordIndicatesFreeChunk(long word) {
- return (word & 0x1L) == 0x1L;
+ public static boolean indicatesFreeChunk(Address cur) {
+ FreeChunk f = new FreeChunk(cur);
+ return f.isFree();
}
public boolean isFree() {
- Debugger dbg = VM.getVM().getDebugger();
- Address prev = prevField.getValue(addr);
- return secondWordIndicatesFreeChunk(dbg.getAddressValue(prev));
+ if (VM.getVM().isCompressedOopsEnabled()) {
+ Mark mark = new Mark(sizeField.getValue(addr));
+ return mark.isCmsFreeChunk();
+ } else {
+ Address prev = prevField.getValue(addr);
+ Debugger dbg = VM.getVM().getDebugger();
+ long word = dbg.getAddressValue(prev);
+ return (word & 0x1L) == 0x1L;
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java Tue Jun 17 15:27:05 2008 -0700
@@ -0,0 +1,72 @@
+/*
+ * @(#)FreeList.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 FreeList 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("FreeList");
+ sizeField = type.getCIntegerField("_size");
+ countField = type.getCIntegerField("_count");
+ headerSize = type.getSize();
+ }
+
+ // Fields
+ private static CIntegerField sizeField;
+ private static CIntegerField countField;
+ private static long headerSize;
+
+ //Constructor
+ public FreeList(Address address) {
+ super(address);
+ }
+
+ // Accessors
+ public long size() {
+ return sizeField.getValue(addr);
+ }
+
+ public long count() {
+ return countField.getValue(addr);
+ }
+
+ public static long sizeOf() {
+ return headerSize;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/LinearAllocBlock.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 LinearAllocBlock 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("LinearAllocBlock");
+ word_sizeField= type.getCIntegerField("_word_size");
+ }
+
+ // Fields
+ private static CIntegerField word_sizeField;
+
+ // Accessors
+ public long word_size() {
+ return word_sizeField.getValue(addr);
+ }
+
+ // Constructor
+ public LinearAllocBlock(Address addr) {
+ super(addr);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java Tue Jun 17 15:27:05 2008 -0700
@@ -79,6 +79,11 @@
noHashInPlace = db.lookupLongConstant("markOopDesc::no_hash_in_place").longValue();
noLockInPlace = db.lookupLongConstant("markOopDesc::no_lock_in_place").longValue();
maxAge = db.lookupLongConstant("markOopDesc::max_age").longValue();
+
+ /* Constants in markOop used by CMS. */
+ cmsShift = db.lookupLongConstant("markOopDesc::cms_shift").longValue();
+ cmsMask = db.lookupLongConstant("markOopDesc::cms_mask").longValue();
+ sizeShift = db.lookupLongConstant("markOopDesc::size_shift").longValue();
}
// Field accessors
@@ -120,6 +125,11 @@
private static long maxAge;
+ /* Constants in markOop used by CMS. */
+ private static long cmsShift;
+ private static long cmsMask;
+ private static long sizeShift;
+
public Mark(Address addr) {
super(addr);
}
@@ -290,4 +300,11 @@
//
// // Recover address of oop from encoded form used in mark
// inline void* decode_pointer() { return clear_lock_bits(); }
+
+ // Copy markOop methods for CMS here.
+ public boolean isCmsFreeChunk() {
+ return isUnlocked() &&
+ (Bits.maskBitsLong(value() >> cmsShift, cmsMask) & 0x1L) == 0x1L;
+ }
+ public long getSize() { return (long)(value() >> sizeShift); }
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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); }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
}
--- a/hotspot/make/hotspot_version Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/make/jprt.config Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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}
--- a/hotspot/make/jprt.properties Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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}
+
--- a/hotspot/make/solaris/makefiles/amd64.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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")
--- a/hotspot/make/solaris/makefiles/debug.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/make/solaris/makefiles/dtrace.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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}")
--- a/hotspot/make/solaris/makefiles/fastdebug.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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 *_<arch>.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<level> -g<level>
--- a/hotspot/make/solaris/makefiles/jvmg.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/make/solaris/makefiles/optimized.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/make/solaris/makefiles/product.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/make/solaris/makefiles/sparc.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/make/solaris/makefiles/sparcWorks.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
#
--- a/hotspot/make/solaris/makefiles/sparcv9.make Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
};
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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:
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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(
--- a/hotspot/src/cpu/x86/vm/assembler_x86_32.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/cpu/x86/vm/assembler_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/cpu/x86/vm/assembler_x86_64.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
}
--- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
--- a/hotspot/src/cpu/x86/vm/relocInfo_x86.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
};
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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) %{
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/share/vm/adlc/forms.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/adlc/formssel.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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",
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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<ciField*>* 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;
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
)
}
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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));
}
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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) */ \
\
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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");
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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 {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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
+};
+
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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) \
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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_<os_family>.inline.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
};
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
};
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
};
--- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
--- a/hotspot/src/share/vm/includeDB_core Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/src/share/vm/includeDB_core Tue Jun 17 15:27:05 2008 -0700
@@ -3492,6 +3492,7 @@
relocInfo_<arch>.cpp assembler.inline.hpp
relocInfo_<arch>.cpp assembler_<arch_model>.inline.hpp
relocInfo_<arch>.cpp nativeInst_<arch>.hpp
+relocInfo_<arch>.cpp oop.inline.hpp
relocInfo_<arch>.cpp relocInfo.hpp
relocInfo_<arch>.cpp safepoint.hpp
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Tue Jun 17 15:27:05 2008 -0700
@@ -1,7 +1,25 @@
<?xml version="1.0"?>
<!--
- Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ Copyright 1997-2000 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.
-->
<!DOCTYPE processcode [
<!ELEMENT processcode ANY>
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Tue Jun 17 15:27:05 2008 -0700
@@ -1,10 +1,29 @@
<?xml version="1.0"?>
<!--
- Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ Copyright 1997-2000 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.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="processcode">
<xsl:text>
@@ -15,7 +34,6 @@
</xsl:text>
-<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
</xsl:template>
</xsl:stylesheet>
--- a/hotspot/src/share/vm/memory/space.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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());
}
}
--- a/hotspot/src/share/vm/oops/arrayOop.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/oops/instanceOop.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
}
};
--- a/hotspot/src/share/vm/oops/markOop.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
};
--- a/hotspot/src/share/vm/oops/methodDataOop.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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() {
--- a/hotspot/src/share/vm/oops/oop.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/callnode.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/callnode.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/opto/cfgnode.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/opto/chaitin.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/classes.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/compile.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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:
--- a/hotspot/src/share/vm/opto/connode.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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---------------------------------------
--- a/hotspot/src/share/vm/opto/connode.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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-------------------------------------
--- a/hotspot/src/share/vm/opto/doCall.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/opto/escape.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/graphKit.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/opto/lcm.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/library_call.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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,
--- a/hotspot/src/share/vm/opto/loopnode.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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 ) {
--- a/hotspot/src/share/vm/opto/loopopts.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/matcher.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/matcher.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/memnode.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/memnode.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/node.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/share/vm/opto/node.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/output.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/parse1.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/opto/type.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
}
--- a/hotspot/src/share/vm/opto/type.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/runtime/globals.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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") \
--- a/hotspot/src/share/vm/runtime/java.hpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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() {
--- a/hotspot/src/share/vm/runtime/thread.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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);
+ }
}
}
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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_<os>_<cpu>.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, \
--- a/hotspot/test/compiler/6659207/Test.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
*
*/
--- a/hotspot/test/compiler/6661247/Test.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
*
*/
--- a/hotspot/test/compiler/6663621/IVTest.java Tue Jun 10 10:22:49 2008 -0700
+++ b/hotspot/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.
*
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+ }
+}