--- old/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java 2012-10-08 20:34:50.729860216 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java 2012-10-08 20:34:50.550175669 +0200 @@ -89,6 +89,7 @@ public Address getAddressAt (long offset) throws UnmappedAddressException, UnalignedAddressException; /** Returns the decoded address at the given offset */ public Address getCompOopAddressAt (long offset) throws UnmappedAddressException, UnalignedAddressException; + public Address getCompKlassAddressAt (long offset) throws UnmappedAddressException, UnalignedAddressException; // // Java-related routines --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java 2012-10-08 20:34:52.105797418 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java 2012-10-08 20:34:51.930155281 +0200 @@ -121,6 +121,9 @@ public long getHeapOopSize(); public long getNarrowOopBase(); public int getNarrowOopShift(); + public long getKlassPtrSize(); + public long getNarrowKlassBase(); + public int getNarrowKlassShift(); public ReadResult readBytesFromProcess(long address, long numBytes) throws DebuggerException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java 2012-10-08 20:34:53.496062778 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java 2012-10-08 20:34:53.305838672 +0200 @@ -58,6 +58,10 @@ protected long heapOopSize; protected long narrowOopBase; // heap base for compressed oops. protected int narrowOopShift; // shift to decode compressed oops. + // class metadata space + protected long klassPtrSize; + protected long narrowKlassBase; // heap base for compressed klass ptrs. + protected int narrowKlassShift; // shift to decode compressed klass ptrs. // Should be initialized if desired by calling initCache() private PageCache cache; @@ -159,10 +163,14 @@ javaPrimitiveTypesConfigured = true; } - public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift) { + public void putHeapConst(long heapOopSize, long klassPtrSize, long narrowOopBase, int narrowOopShift, + long narrowKlassBase, int narrowKlassShift) { this.heapOopSize = heapOopSize; + this.klassPtrSize = klassPtrSize; this.narrowOopBase = narrowOopBase; this.narrowOopShift = narrowOopShift; + this.narrowKlassBase = narrowKlassBase; + this.narrowKlassShift = narrowKlassShift; } /** May be called by subclasses if desired to initialize the page @@ -464,6 +472,15 @@ return value; } + protected long readCompKlassAddressValue(long address) + throws UnmappedAddressException, UnalignedAddressException { + long value = readCInteger(address, getKlassPtrSize(), true); + if (value != 0) { + value = (long)(narrowKlassBase + (long)(value << narrowKlassShift)); + } + return value; + } + protected void writeAddressValue(long address, long value) throws UnmappedAddressException, UnalignedAddressException { writeCInteger(address, machDesc.getAddressSize(), value); @@ -551,4 +568,15 @@ public int getNarrowOopShift() { return narrowOopShift; } + + public long getKlassPtrSize() { + return klassPtrSize; + } + + public long getNarrowKlassBase() { + return narrowKlassBase; + } + public int getNarrowKlassShift() { + return narrowKlassShift; + } } --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java 2012-10-08 20:34:54.850937624 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java 2012-10-08 20:34:54.663436868 +0200 @@ -42,5 +42,7 @@ long jintSize, long jlongSize, long jshortSize); - public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift); + public void putHeapConst(long heapOopSize, long klassPtrSize, + long narrowKlassBase, int narrowKlassShift, + long narrowOopBase, int narrowOopShift); } --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java 2012-10-08 20:34:56.200945134 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java 2012-10-08 20:34:56.001361405 +0200 @@ -79,6 +79,11 @@ return debugger.readCompOopAddress(addr + offset); } + public Address getCompKlassAddressAt(long offset) + throws UnalignedAddressException, UnmappedAddressException { + return debugger.readCompOopAddress(addr + offset); + } + // // Java-related routines // --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java 2012-10-08 20:34:57.533068034 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java 2012-10-08 20:34:57.352334737 +0200 @@ -46,6 +46,7 @@ throws DebuggerException; public BsdAddress readAddress(long address) throws DebuggerException; public BsdAddress readCompOopAddress(long address) throws DebuggerException; + public BsdAddress readCompKlassAddress(long address) throws DebuggerException; public BsdOopHandle readOopHandle(long address) throws DebuggerException; public BsdOopHandle readCompOopHandle(long address) throws DebuggerException; public long[] getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java 2012-10-08 20:34:58.948603705 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java 2012-10-08 20:34:58.677928311 +0200 @@ -431,6 +431,12 @@ return (value == 0 ? null : new BsdAddress(this, value)); } + public BsdAddress readCompKlassAddress(long address) + throws UnmappedAddressException, UnalignedAddressException { + long value = readCompKlassAddressValue(address); + return (value == 0 ? null : new BsdAddress(this, value)); + } + /** From the BsdDebugger interface */ public BsdOopHandle readOopHandle(long address) throws UnmappedAddressException, UnalignedAddressException, --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java 2012-10-08 20:35:00.471575949 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java 2012-10-08 20:35:00.287031139 +0200 @@ -80,6 +80,10 @@ return new DummyAddress(debugger, badLong); } + public Address getCompKlassAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException { + return new DummyAddress(debugger, badLong); + } + // // Java-related routines // --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java 2012-10-08 20:35:01.843346093 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java 2012-10-08 20:35:01.657541501 +0200 @@ -79,6 +79,11 @@ return debugger.readCompOopAddress(addr + offset); } + public Address getCompKlassAddressAt(long offset) + throws UnalignedAddressException, UnmappedAddressException { + return debugger.readCompKlassAddress(addr + offset); + } + // // Java-related routines // --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java 2012-10-08 20:35:03.443326012 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java 2012-10-08 20:35:03.269710571 +0200 @@ -46,6 +46,7 @@ throws DebuggerException; public LinuxAddress readAddress(long address) throws DebuggerException; public LinuxAddress readCompOopAddress(long address) throws DebuggerException; + public LinuxAddress readCompKlassAddress(long address) throws DebuggerException; public LinuxOopHandle readOopHandle(long address) throws DebuggerException; public LinuxOopHandle readCompOopHandle(long address) throws DebuggerException; public long[] getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java 2012-10-08 20:35:04.768259430 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java 2012-10-08 20:35:04.585670782 +0200 @@ -429,6 +429,12 @@ return (value == 0 ? null : new LinuxAddress(this, value)); } + public LinuxAddress readCompKlassAddress(long address) + throws UnmappedAddressException, UnalignedAddressException { + long value = readCompKlassAddressValue(address); + return (value == 0 ? null : new LinuxAddress(this, value)); + } + /** From the LinuxDebugger interface */ public LinuxOopHandle readOopHandle(long address) throws UnmappedAddressException, UnalignedAddressException, --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java 2012-10-08 20:35:06.264322270 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java 2012-10-08 20:35:06.085457315 +0200 @@ -76,6 +76,10 @@ return debugger.readCompOopAddress(addr + offset); } + public Address getCompKlassAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException { + return debugger.readCompKlassAddress(addr + offset); + } + // // Java-related routines // --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java 2012-10-08 20:35:07.589648808 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java 2012-10-08 20:35:07.411801342 +0200 @@ -47,6 +47,7 @@ throws DebuggerException; public ProcAddress readAddress(long address) throws DebuggerException; public ProcAddress readCompOopAddress(long address) throws DebuggerException; + public ProcAddress readCompKlassAddress(long address) throws DebuggerException; public ProcOopHandle readOopHandle(long address) throws DebuggerException; public ProcOopHandle readCompOopHandle(long address) throws DebuggerException; public long[] getThreadIntegerRegisterSet(int tid) throws DebuggerException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java 2012-10-08 20:35:08.918121034 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java 2012-10-08 20:35:08.734950003 +0200 @@ -351,6 +351,12 @@ return (value == 0 ? null : new ProcAddress(this, value)); } + public ProcAddress readCompKlassAddress(long address) + throws UnmappedAddressException, UnalignedAddressException { + long value = readCompKlassAddressValue(address); + return (value == 0 ? null : new ProcAddress(this, value)); + } + /** From the ProcDebugger interface */ public ProcOopHandle readOopHandle(long address) throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java 2012-10-08 20:35:10.343676547 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java 2012-10-08 20:35:10.154290831 +0200 @@ -74,6 +74,9 @@ public Address getCompOopAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException { return debugger.readCompOopAddress(addr + offset); } + public Address getCompKlassAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException { + return debugger.readCompKlassAddress(addr + offset); + } // // Java-related routines --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java 2012-10-08 20:35:11.678155894 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java 2012-10-08 20:35:11.494315719 +0200 @@ -68,6 +68,9 @@ public long getHeapOopSize() throws RemoteException; public long getNarrowOopBase() throws RemoteException; public int getNarrowOopShift() throws RemoteException; + public long getKlassPtrSize() throws RemoteException; + public long getNarrowKlassBase() throws RemoteException; + public int getNarrowKlassShift() throws RemoteException; public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java 2012-10-08 20:35:12.997848814 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java 2012-10-08 20:35:12.812305326 +0200 @@ -99,7 +99,10 @@ javaPrimitiveTypesConfigured = true; narrowOopBase = remoteDebugger.getNarrowOopBase(); narrowOopShift = remoteDebugger.getNarrowOopShift(); + narrowKlassBase = remoteDebugger.getNarrowKlassBase(); + narrowKlassShift = remoteDebugger.getNarrowKlassShift(); heapOopSize = remoteDebugger.getHeapOopSize(); + klassPtrSize = remoteDebugger.getKlassPtrSize(); } catch (RemoteException e) { throw new DebuggerException(e); @@ -319,6 +322,12 @@ return (value == 0 ? null : new RemoteAddress(this, value)); } + RemoteAddress readCompKlassAddress(long address) + throws UnmappedAddressException, UnalignedAddressException { + long value = readCompKlassAddressValue(address); + return (value == 0 ? null : new RemoteAddress(this, value)); + } + RemoteOopHandle readOopHandle(long address) throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { long value = readAddressValue(address); --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java 2012-10-08 20:35:14.308474304 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java 2012-10-08 20:35:14.133724971 +0200 @@ -126,6 +126,18 @@ return debugger.getNarrowOopShift(); } + public long getKlassPtrSize() throws RemoteException { + return debugger.getHeapOopSize(); + } + + public long getNarrowKlassBase() throws RemoteException { + return debugger.getNarrowKlassBase(); + } + + public int getNarrowKlassShift() throws RemoteException { + return debugger.getNarrowKlassShift(); + } + public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException { ThreadProxy t1 = getThreadProxy(addrOrId1, isAddress1); --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java 2012-10-08 20:35:15.625526627 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java 2012-10-08 20:35:15.432174790 +0200 @@ -76,6 +76,10 @@ return debugger.readCompOopAddress(addr + offset); } + public Address getCompKlassAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException { + return debugger.readCompKlassAddress(addr + offset); + } + // // Java-related routines // --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java 2012-10-08 20:35:16.931559211 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java 2012-10-08 20:35:16.755643615 +0200 @@ -46,6 +46,7 @@ throws DebuggerException; public WindbgAddress readAddress(long address) throws DebuggerException; public WindbgAddress readCompOopAddress(long address) throws DebuggerException; + public WindbgAddress readCompKlassAddress(long address) throws DebuggerException; public WindbgOopHandle readOopHandle(long address) throws DebuggerException; public WindbgOopHandle readCompOopHandle(long address) throws DebuggerException; --- old/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java 2012-10-08 20:35:18.277325560 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java 2012-10-08 20:35:18.073740191 +0200 @@ -321,6 +321,11 @@ return (WindbgAddress) newAddress(readCompOopAddressValue(address)); } + public WindbgAddress readCompKlassAddress(long address) + throws UnmappedAddressException, UnalignedAddressException { + return (WindbgAddress) newAddress(readCompKlassAddressValue(address)); + } + /** From the WindbgDebugger interface */ public WindbgOopHandle readOopHandle(long address) throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { --- old/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java 2012-10-08 20:35:19.732375792 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java 2012-10-08 20:35:19.539955688 +0200 @@ -53,6 +53,8 @@ private static AddressField narrowOopBaseField; private static CIntegerField narrowOopShiftField; + private static AddressField narrowKlassBaseField; + private static CIntegerField narrowKlassShiftField; static { VM.registerVMInitializedObserver(new Observer() { @@ -86,6 +88,8 @@ narrowOopBaseField = type.getAddressField("_narrow_oop._base"); narrowOopShiftField = type.getCIntegerField("_narrow_oop._shift"); + narrowKlassBaseField = type.getAddressField("_narrow_klass._base"); + narrowKlassShiftField = type.getCIntegerField("_narrow_klass._shift"); } public Universe() { @@ -111,6 +115,19 @@ return (int)narrowOopShiftField.getValue(); } + public static long getNarrowKlassBase() { + if (narrowKlassBaseField.getValue() == null) { + return 0; + } else { + return narrowKlassBaseField.getValue().minus(null); + } + } + + public static int getNarrowKlassShift() { + return (int)narrowKlassShiftField.getValue(); + } + + /** Returns "TRUE" iff "p" points into the allocated area of the heap. */ public boolean isIn(Address p) { return heap().isIn(p); --- old/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java 2012-10-08 20:35:21.043081017 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java 2012-10-08 20:35:20.862782315 +0200 @@ -59,7 +59,7 @@ if (headerSize != 0) { return headerSize; } - if (VM.getVM().isCompressedHeadersEnabled()) { + if (VM.getVM().isCompressedKlassPointersEnabled()) { headerSize = typeSize; } else { headerSize = VM.getVM().alignUp(typeSize + VM.getVM().getIntSize(), @@ -80,7 +80,7 @@ if (lengthOffsetInBytes != 0) { return lengthOffsetInBytes; } - if (VM.getVM().isCompressedHeadersEnabled()) { + if (VM.getVM().isCompressedKlassPointersEnabled()) { lengthOffsetInBytes = typeSize - VM.getVM().getIntSize(); } else { lengthOffsetInBytes = typeSize; --- old/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java 2012-10-08 20:35:22.332912923 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java 2012-10-08 20:35:22.143398923 +0200 @@ -53,7 +53,7 @@ // Returns header size in bytes. public static long getHeaderSize() { - if (VM.getVM().isCompressedHeadersEnabled()) { + if (VM.getVM().isCompressedKlassPointersEnabled()) { return typeSize - VM.getVM().getIntSize(); } else { return typeSize; --- old/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java 2012-10-08 20:35:23.637355376 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java 2012-10-08 20:35:23.461824595 +0200 @@ -27,7 +27,6 @@ import sun.jvm.hotspot.runtime.VMObject; import sun.jvm.hotspot.debugger.*; -// The class for an C int field simply provides access to the value. public class MetadataField extends Field { public MetadataField(sun.jvm.hotspot.types.AddressField vmField, long startOffset) { --- old/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java 2012-10-08 20:35:24.906338093 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java 2012-10-08 20:35:24.730613126 +0200 @@ -47,10 +47,7 @@ Type type = db.lookupType("oopDesc"); mark = new CIntField(type.getCIntegerField("_mark"), 0); klass = new MetadataField(type.getAddressField("_metadata._klass"), 0); - if (VM.getVM().isCompressedHeadersEnabled()) { - // compressedKlass = new CIntField(type.getCIntegerField("_metadata._compressed_klass"), 0); - throw new InternalError("unimplemented"); - } + compressedKlass = new NarrowKlassField(type.getAddressField("_metadata._compressed_klass"), 0); headerSize = type.getSize(); } @@ -74,13 +71,13 @@ private static CIntField mark; private static MetadataField klass; - private static CIntField compressedKlass; + private static NarrowKlassField compressedKlass; // Accessors for declared fields public Mark getMark() { return new Mark(getHandle()); } public Klass getKlass() { - if (VM.getVM().isCompressedHeadersEnabled()) { - throw new InternalError("unimplemented"); + if (VM.getVM().isCompressedKlassPointersEnabled()) { + return (Klass)compressedKlass.getValue(getHandle()); } else { return (Klass)klass.getValue(getHandle()); } @@ -150,7 +147,7 @@ void iterateFields(OopVisitor visitor, boolean doVMFields) { if (doVMFields) { visitor.doCInt(mark, true); - if (VM.getVM().isCompressedHeadersEnabled()) { + if (VM.getVM().isCompressedKlassPointersEnabled()) { throw new InternalError("unimplemented"); } else { visitor.doMetadata(klass, true); @@ -210,8 +207,8 @@ if (handle == null) { return null; } - if (VM.getVM().isCompressedHeadersEnabled()) { - throw new InternalError("Unimplemented"); + if (VM.getVM().isCompressedKlassPointersEnabled()) { + return (Klass)Metadata.instantiateWrapperFor(handle.getCompKlassAddressAt(compressedKlass.getOffset())); } else { return (Klass)Metadata.instantiateWrapperFor(handle.getAddressAt(klass.getOffset())); } --- old/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java 2012-10-08 20:35:26.220076206 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java 2012-10-08 20:35:26.014261108 +0200 @@ -63,11 +63,7 @@ /** get Klass* field at offset hc_klass_offset from a java.lang.Class object */ public static Klass asKlass(Oop aClass) { - if (VM.getVM().isCompressedHeadersEnabled()) { - throw new InternalError("unimplemented"); - } else { - return (Klass)Metadata.instantiateWrapperFor(aClass.getHandle().getAddressAt(klassOffset)); - } + return (Klass)Metadata.instantiateWrapperFor(aClass.getHandle().getAddressAt(klassOffset)); } /** get oop_size field at offset oop_size_offset from a java.lang.Class object */ --- old/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java 2012-10-08 20:35:27.568629268 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java 2012-10-08 20:35:27.381986620 +0200 @@ -103,6 +103,7 @@ private int logMinObjAlignmentInBytes; private int heapWordSize; private int heapOopSize; + private int klassPtrSize; private int oopSize; /** This is only present in a non-core build */ private CodeCache codeCache; @@ -129,7 +130,7 @@ private static CIntegerType boolType; private Boolean sharingEnabled; private Boolean compressedOopsEnabled; - private Boolean compressedHeadersEnabled; + private Boolean compressedKlassPointersEnabled; // command line flags supplied to VM - see struct Flag in globals.hpp public static final class Flag { @@ -350,6 +351,12 @@ } else { heapOopSize = (int)getOopSize(); } + + if (isCompressedKlassPointersEnabled()) { + klassPtrSize = (int)getIntSize(); + } else { + klassPtrSize = (int)getOopSize(); // same as an oop + } } /** This could be used by a reflective runtime system */ @@ -374,8 +381,9 @@ ((Observer) iter.next()).update(null, null); } - debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), - Universe.getNarrowOopShift()); + debugger.putHeapConst(soleInstance.getHeapOopSize(), soleInstance.getKlassPtrSize(), + Universe.getNarrowOopBase(), Universe.getNarrowOopShift(), + Universe.getNarrowKlassBase(), Universe.getNarrowKlassShift()); } /** This is used by the debugging system */ @@ -536,6 +544,10 @@ public int getHeapOopSize() { return heapOopSize; } + + public int getKlassPtrSize() { + return klassPtrSize; + } /** Utility routine for getting data structure alignment correct */ public long alignUp(long size, long alignment) { return (size + alignment - 1) & ~(alignment - 1); @@ -784,13 +796,13 @@ return compressedOopsEnabled.booleanValue(); } - public boolean isCompressedHeadersEnabled() { - if (compressedHeadersEnabled == null) { - Flag flag = getCommandLineFlag("UseCompressedHeaders"); - compressedHeadersEnabled = (flag == null) ? Boolean.FALSE: + public boolean isCompressedKlassPointersEnabled() { + if (compressedKlassPointersEnabled == null) { + Flag flag = getCommandLineFlag("UseCompressedKlassPointers"); + compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE: (flag.getBool()? Boolean.TRUE: Boolean.FALSE); } - return compressedHeadersEnabled.booleanValue(); + return compressedKlassPointersEnabled.booleanValue(); } public int getObjectAlignmentInBytes() { --- old/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java 2012-10-08 20:35:28.998611203 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java 2012-10-08 20:35:28.812913096 +0200 @@ -53,9 +53,8 @@ private static void initialize(TypeDataBase db) { Type type = db.lookupType("oopDesc"); - if (VM.getVM().isCompressedHeadersEnabled()) { - // klassField = type.getNarrowOopField("_metadata._compressed_klass"); - throw new InternalError("unimplemented"); + if (VM.getVM().isCompressedKlassPointersEnabled()) { + klassField = type.getAddressField("_metadata._compressed_klass"); } else { klassField = type.getAddressField("_metadata._klass"); } @@ -70,7 +69,11 @@ } try { // Try to instantiate the Klass - Metadata.instantiateWrapperFor(klassField.getValue(oop)); + if (VM.getVM().isCompressedKlassPointersEnabled()) { + Metadata.instantiateWrapperFor(oop.getCompKlassAddressAt(klassField.getOffset())); + } else { + Metadata.instantiateWrapperFor(klassField.getValue(oop)); + } return true; } catch (AddressException e) { --- old/src/cpu/sparc/vm/assembler_sparc.cpp 2012-10-08 20:35:30.563588935 +0200 +++ new/src/cpu/sparc/vm/assembler_sparc.cpp 2012-10-08 20:35:30.358817661 +0200 @@ -1641,6 +1641,21 @@ } +void MacroAssembler::set_narrow_klass(Klass* k, Register d) { + assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int klass_index = oop_recorder()->find_index(k); + RelocationHolder rspec = metadata_Relocation::spec(klass_index); + narrowOop encoded_k = oopDesc::encode_klass(k); + + assert_not_delayed(); + // Relocation with special format (see relocInfo_sparc.hpp). + relocate(rspec, 1); + // Assembler::sethi(encoded_k, d); + emit_long( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(encoded_k) ); + // Don't add relocation for 'add'. Do patching during 'sethi' processing. + add(d, low10(encoded_k), d); + +} void MacroAssembler::align(int modulus) { while (offset() % modulus != 0) nop(); @@ -4660,7 +4675,7 @@ // if this changes, change that. if (UseCompressedKlassPointers) { lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass); - decode_heap_oop_not_null(klass); + decode_klass_not_null(klass); } else { ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass); } @@ -4669,7 +4684,7 @@ void MacroAssembler::store_klass(Register klass, Register dst_oop) { if (UseCompressedKlassPointers) { assert(dst_oop != klass, "not enough registers"); - encode_heap_oop_not_null(klass); + encode_klass_not_null(klass); st(klass, dst_oop, oopDesc::klass_offset_in_bytes()); } else { st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes()); @@ -4829,17 +4844,58 @@ // pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(src, LogMinObjAlignmentInBytes, dst); if (Universe::narrow_oop_base() != NULL) add(dst, G6_heapbase, dst); } +void MacroAssembler::encode_klass_not_null(Register r) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + assert (UseCompressedKlassPointers, "must be compressed"); + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + if (Universe::narrow_klass_base() != NULL) + sub(r, G6_heapbase, r); + srlx(r, LogKlassAlignmentInBytes, r); +} + +void MacroAssembler::encode_klass_not_null(Register src, Register dst) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + assert (UseCompressedKlassPointers, "must be compressed"); + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + if (Universe::narrow_klass_base() == NULL) { + srlx(src, LogKlassAlignmentInBytes, dst); + } else { + sub(src, G6_heapbase, dst); + srlx(dst, LogKlassAlignmentInBytes, dst); + } +} + +void MacroAssembler::decode_klass_not_null(Register r) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + // Do not add assert code to this unless you change vtableStubs_sparc.cpp + // pd_code_size_limit. + assert (UseCompressedKlassPointers, "must be compressed"); + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + sllx(r, LogKlassAlignmentInBytes, r); + if (Universe::narrow_klass_base() != NULL) + add(r, G6_heapbase, r); +} + +void MacroAssembler::decode_klass_not_null(Register src, Register dst) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + // Do not add assert code to this unless you change vtableStubs_sparc.cpp + // pd_code_size_limit. + assert (UseCompressedKlassPointers, "must be compressed"); + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + sllx(src, LogKlassAlignmentInBytes, dst); + if (Universe::narrow_klass_base() != NULL) + add(dst, G6_heapbase, dst); +} + void MacroAssembler::reinit_heapbase() { - if (UseCompressedOops) { - // call indirectly to solve generation ordering problem - AddressLiteral base(Universe::narrow_oop_base_addr()); + if (UseCompressedOops || UseCompressedKlassPointers) { + AddressLiteral base(Universe::narrow_ptrs_base_addr()); load_ptr_contents(base, G6_heapbase); } } --- old/src/cpu/sparc/vm/assembler_sparc.hpp 2012-10-08 20:35:32.209304196 +0200 +++ new/src/cpu/sparc/vm/assembler_sparc.hpp 2012-10-08 20:35:31.950979057 +0200 @@ -2280,6 +2280,11 @@ void encode_heap_oop_not_null(Register src, Register dst); void decode_heap_oop_not_null(Register src, Register dst); + void encode_klass_not_null(Register r); + void decode_klass_not_null(Register r); + void encode_klass_not_null(Register src, Register dst); + void decode_klass_not_null(Register src, Register dst); + // Support for managing the JavaThread pointer (i.e.; the reference to // thread-local information). void get_thread(); // load G2_thread @@ -2409,6 +2414,7 @@ inline void set_metadata (const AddressLiteral& obj_addr, Register d); // same as load_address void set_narrow_oop( jobject obj, Register d ); + void set_narrow_klass( Klass* k, Register d ); // nop padding void align(int modulus); --- old/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp 2012-10-08 20:35:33.898823004 +0200 +++ new/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp 2012-10-08 20:35:33.710733169 +0200 @@ -104,6 +104,11 @@ if (dst->is_address() && !dst->is_stack() && (dst->type() == T_OBJECT || dst->type() == T_ARRAY)) return false; if (src->is_address() && !src->is_stack() && (src->type() == T_OBJECT || src->type() == T_ARRAY)) return false; } + + if (UseCompressedKlassPointers) { + if (src->is_address() && !src->is_stack() && src->type() == T_ADDRESS && + src->as_address_ptr()->disp() == oopDesc::klass_offset_in_bytes()) return false; + } if (dst->is_register()) { if (src->is_address() && Assembler::is_simm13(src->as_address_ptr()->disp())) { @@ -969,8 +974,15 @@ #endif } break; - case T_METADATA: - case T_ADDRESS: __ ld_ptr(base, offset, to_reg->as_register()); break; + case T_METADATA: __ ld_ptr(base, offset, to_reg->as_register()); break; + case T_ADDRESS: + if (UseCompressedKlassPointers && offset == oopDesc::klass_offset_in_bytes()) { + __ lduw(base, offset, to_reg->as_register()); + __ decode_klass_not_null(to_reg->as_register()); + } else { + __ ld_ptr(base, offset, to_reg->as_register()); + } + break; case T_ARRAY : // fall through case T_OBJECT: { @@ -2344,7 +2356,7 @@ if (UseCompressedKlassPointers) { // tmp holds the default type. It currently comes uncompressed after the // load of a constant, so encode it. - __ encode_heap_oop(tmp); + __ encode_klass_not_null(tmp); // load the raw value of the dst klass, since we will be comparing // uncompressed values directly. __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2); --- old/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp 2012-10-08 20:35:35.381562300 +0200 +++ new/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp 2012-10-08 20:35:35.192783409 +0200 @@ -189,7 +189,7 @@ if (UseCompressedKlassPointers) { // Save klass mov(klass, t1); - encode_heap_oop_not_null(t1); + encode_klass_not_null(t1); stw(t1, obj, oopDesc::klass_offset_in_bytes()); } else { st_ptr(klass, obj, oopDesc::klass_offset_in_bytes()); --- old/src/cpu/sparc/vm/relocInfo_sparc.cpp 2012-10-08 20:35:36.741688132 +0200 +++ new/src/cpu/sparc/vm/relocInfo_sparc.cpp 2012-10-08 20:35:36.566393441 +0200 @@ -97,8 +97,8 @@ 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); + assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, "only narrow oops or klasses case"); + jint np = type() == relocInfo::oop_type ? oopDesc::encode_heap_oop((oop)x) : oopDesc::encode_klass((Klass*)x); inst &= ~Assembler::hi22(-1); inst |= Assembler::hi22((intptr_t)np); if (verify_only) { --- old/src/cpu/sparc/vm/sparc.ad 2012-10-08 20:35:38.546364521 +0200 +++ new/src/cpu/sparc/vm/sparc.ad 2012-10-08 20:35:38.322639808 +0200 @@ -557,9 +557,9 @@ int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); int klass_load_size; - if (UseCompressedOops && UseCompressedKlassPointers) { + if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); - if (Universe::narrow_oop_base() == NULL) + if (Universe::narrow_klass_base() == NULL) klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass() else klass_load_size = 3*BytesPerInstWord; @@ -1707,11 +1707,11 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print_cr("\nUEP:"); #ifdef _LP64 - if (UseCompressedOops) { + if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass"); st->print_cr("\tSLL R_G5,3,R_G5"); - if (Universe::narrow_oop_base() != NULL) + if (Universe::narrow_klass_base() != NULL) st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); } else { st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check"); @@ -1942,6 +1942,12 @@ return false; } +bool Matcher::narrow_klass_use_complex_address() { + NOT_LP64(ShouldNotCallThis()); + assert(UseCompressedKlassPointers, "only for compressed klass code"); + return false; +} + // Is it better to copy float constants, or load them directly from memory? // Intel can load a float constant from a direct address, requiring no // extra registers. Most RISCs will have to materialize an address into a @@ -2602,9 +2608,9 @@ int off = __ offset(); __ load_klass(O0, G3_scratch); int klass_load_size; - if (UseCompressedOops && UseCompressedKlassPointers) { + if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); - if (Universe::narrow_oop_base() == NULL) + if (Universe::narrow_klass_base() == NULL) klass_load_size = 2*BytesPerInstWord; else klass_load_size = 3*BytesPerInstWord; @@ -3610,6 +3616,15 @@ interface(CONST_INTER); %} +operand immNKlass() +%{ + match(ConNKlass); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + // NULL Pointer Immediate operand immN0() %{ @@ -6159,6 +6174,17 @@ ins_pipe(ialu_hi_lo_reg); %} +instruct loadConNKlass(iRegN dst, immNKlass src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST * 3/2); + format %{ "SET $src,$dst\t! compressed klass ptr" %} + ins_encode %{ + Register dst = $dst$$Register; + __ set_narrow_klass((Klass*)$src$$constant, dst); + %} + ins_pipe(ialu_hi_lo_reg); +%} + // Materialize long value (predicated by immL_cheap). instruct loadConL_set64(iRegL dst, immL_cheap con, o7RegL tmp) %{ match(Set dst con); @@ -6475,6 +6501,25 @@ ins_pipe(istore_mem_spORreg); %} +instruct storeNKlass(memory dst, iRegN src) %{ + match(Set dst (StoreNKlass dst src)); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "STW $src,$dst\t! compressed klass ptr" %} + ins_encode %{ + Register base = as_Register($dst$$base); + Register index = as_Register($dst$$index); + Register src = $src$$Register; + if (index != G0) { + __ stw(src, base, index); + } else { + __ stw(src, base, $dst$$disp); + } + %} + ins_pipe(istore_mem_spORreg); +%} + instruct storeN0(memory dst, immN0 src) %{ match(Set dst (StoreN dst src)); ins_cost(MEMORY_REF_COST); @@ -6582,6 +6627,23 @@ ins_pipe(ialu_reg); %} +instruct encodeKlass_not_null(iRegN dst, iRegP src) %{ + match(Set dst (EncodePKlass src)); + format %{ "encode_klass_not_null $src, $dst" %} + ins_encode %{ + __ encode_klass_not_null($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeKlass_not_null(iRegP dst, iRegN src) %{ + match(Set dst (DecodeNKlass src)); + format %{ "decode_klass_not_null $src, $dst" %} + ins_encode %{ + __ decode_klass_not_null($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} //----------MemBar Instructions----------------------------------------------- // Memory barrier flavors --- old/src/cpu/sparc/vm/vm_version_sparc.cpp 2012-10-08 20:35:40.305425632 +0200 +++ new/src/cpu/sparc/vm/vm_version_sparc.cpp 2012-10-08 20:35:40.126365400 +0200 @@ -117,6 +117,7 @@ // 32-bit oops don't make sense for the 64-bit VM on sparc // since the 32-bit VM has the same registers and smaller objects. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); #endif // _LP64 #ifdef COMPILER2 // Indirect branch is the same cost as direct --- old/src/cpu/sparc/vm/vtableStubs_sparc.cpp 2012-10-08 20:35:41.644213132 +0200 +++ new/src/cpu/sparc/vm/vtableStubs_sparc.cpp 2012-10-08 20:35:41.461168624 +0200 @@ -220,13 +220,13 @@ const int basic = 5*BytesPerInstWord + // shift;add for load_klass (only shift with zero heap based) (UseCompressedKlassPointers ? - ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); + ((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return basic + slop; } else { const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + // shift;add for load_klass (only shift with zero heap based) (UseCompressedKlassPointers ? - ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); + ((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return (basic + slop); } } --- old/src/cpu/x86/vm/assembler_x86.cpp 2012-10-08 20:35:43.143023808 +0200 +++ new/src/cpu/x86/vm/assembler_x86.cpp 2012-10-08 20:35:42.902660672 +0200 @@ -6936,7 +6936,7 @@ #ifdef ASSERT // TraceBytecodes does not use r12 but saves it over the call, so don't verify // r12 is the heapbase. - LP64_ONLY(if (UseCompressedOops && !TraceBytecodes) verify_heapbase("call_VM_base");) + LP64_ONLY(if ((UseCompressedOops || UseCompressedKlassPointers) && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?");) #endif // ASSERT assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result"); @@ -10036,7 +10036,7 @@ #ifdef _LP64 if (UseCompressedKlassPointers) { movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); - decode_heap_oop_not_null(dst); + decode_klass_not_null(dst); } else #endif movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); @@ -10047,15 +10047,10 @@ if (UseCompressedKlassPointers) { assert (Universe::heap() != NULL, "java heap should be initialized"); movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); - if (Universe::narrow_oop_shift() != 0) { - assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - if (LogMinObjAlignmentInBytes == Address::times_8) { - movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset())); - } else { - // OK to use shift since we don't need to preserve flags. - shlq(dst, LogMinObjAlignmentInBytes); - movq(dst, Address(r12_heapbase, dst, Address::times_1, Klass::prototype_header_offset())); - } + if (Universe::narrow_klass_shift() != 0) { + assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); + movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset())); } else { movq(dst, Address(dst, Klass::prototype_header_offset())); } @@ -10070,7 +10065,7 @@ void MacroAssembler::store_klass(Register dst, Register src) { #ifdef _LP64 if (UseCompressedKlassPointers) { - encode_heap_oop_not_null(src); + encode_klass_not_null(src); movl(Address(dst, oopDesc::klass_offset_in_bytes()), src); } else #endif @@ -10152,12 +10147,12 @@ #ifdef ASSERT void MacroAssembler::verify_heapbase(const char* msg) { - assert (UseCompressedOops, "should be compressed"); + assert (UseCompressedOops || UseCompressedKlassPointers, "should be compressed"); assert (Universe::heap() != NULL, "java heap should be initialized"); if (CheckCompressedOops) { Label ok; push(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); + cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); jcc(Assembler::equal, ok); STOP(msg); bind(ok); @@ -10295,6 +10290,74 @@ } } +void MacroAssembler::encode_klass_not_null(Register r) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); +#ifdef ASSERT + verify_heapbase("MacroAssembler::encode_klass_not_null: heap base corrupted?"); +#endif + if (Universe::narrow_klass_base() != NULL) { + subq(r, r12_heapbase); + } + if (Universe::narrow_klass_shift() != 0) { + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + shrq(r, LogKlassAlignmentInBytes); + } +} + +void MacroAssembler::encode_klass_not_null(Register dst, Register src) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); +#ifdef ASSERT + verify_heapbase("MacroAssembler::encode_klass_not_null2: heap base corrupted?"); +#endif + if (dst != src) { + movq(dst, src); + } + if (Universe::narrow_klass_base() != NULL) { + subq(dst, r12_heapbase); + } + if (Universe::narrow_klass_shift() != 0) { + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + shrq(dst, LogKlassAlignmentInBytes); + } +} + +void MacroAssembler::decode_klass_not_null(Register r) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + // Note: it will change flags + assert (UseCompressedKlassPointers, "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. + if (Universe::narrow_klass_shift() != 0) { + assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + shlq(r, LogKlassAlignmentInBytes); + if (Universe::narrow_klass_base() != NULL) { + addq(r, r12_heapbase); + } + } else { + assert (Universe::narrow_klass_base() == NULL, "sanity"); + } +} + +void MacroAssembler::decode_klass_not_null(Register dst, Register src) { + assert(Metaspace::is_initialized(), "metaspace should be initialized"); + // Note: it will change flags + assert (UseCompressedKlassPointers, "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. + if (Universe::narrow_klass_shift() != 0) { + assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); + leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + } else { + assert (Universe::narrow_klass_base() == NULL, "sanity"); + if (dst != src) { + movq(dst, src); + } + } +} + void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { assert (UseCompressedOops, "should only be used for compressed headers"); assert (Universe::heap() != NULL, "java heap should be initialized"); @@ -10313,6 +10376,22 @@ mov_narrow_oop(dst, oop_index, rspec); } +void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { + assert (UseCompressedKlassPointers, "should only be used for compressed headers"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int klass_index = oop_recorder()->find_index(k); + RelocationHolder rspec = metadata_Relocation::spec(klass_index); + mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec); +} + +void MacroAssembler::set_narrow_klass(Address dst, Klass* k) { + assert (UseCompressedKlassPointers, "should only be used for compressed headers"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int klass_index = oop_recorder()->find_index(k); + RelocationHolder rspec = metadata_Relocation::spec(klass_index); + mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec); +} + void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) { assert (UseCompressedOops, "should only be used for compressed headers"); assert (Universe::heap() != NULL, "java heap should be initialized"); @@ -10331,9 +10410,25 @@ Assembler::cmp_narrow_oop(dst, oop_index, rspec); } +void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) { + assert (UseCompressedKlassPointers, "should only be used for compressed headers"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int klass_index = oop_recorder()->find_index(k); + RelocationHolder rspec = metadata_Relocation::spec(klass_index); + Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec); +} + +void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) { + assert (UseCompressedKlassPointers, "should only be used for compressed headers"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int klass_index = oop_recorder()->find_index(k); + RelocationHolder rspec = metadata_Relocation::spec(klass_index); + Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec); +} + void MacroAssembler::reinit_heapbase() { - if (UseCompressedOops) { - movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); + if (UseCompressedOops || UseCompressedKlassPointers) { + movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); } } #endif // _LP64 --- old/src/cpu/x86/vm/assembler_x86.hpp 2012-10-08 20:35:44.949664301 +0200 +++ new/src/cpu/x86/vm/assembler_x86.hpp 2012-10-08 20:35:44.754845189 +0200 @@ -2083,6 +2083,15 @@ void cmp_narrow_oop(Register dst, jobject obj); void cmp_narrow_oop(Address dst, jobject obj); + void encode_klass_not_null(Register r); + void decode_klass_not_null(Register r); + void encode_klass_not_null(Register dst, Register src); + void decode_klass_not_null(Register dst, Register src); + void set_narrow_klass(Register dst, Klass* k); + void set_narrow_klass(Address dst, Klass* k); + void cmp_narrow_klass(Register dst, Klass* k); + void cmp_narrow_klass(Address dst, Klass* k); + // if heap base register is used - reinit it with the correct value void reinit_heapbase(); --- old/src/cpu/x86/vm/c1_FrameMap_x86.hpp 2012-10-08 20:35:46.430377040 +0200 +++ new/src/cpu/x86/vm/c1_FrameMap_x86.hpp 2012-10-08 20:35:46.247209943 +0200 @@ -148,7 +148,7 @@ static int adjust_reg_range(int range) { // Reduce the number of available regs (to free r12) in case of compressed oops - if (UseCompressedOops) return range - 1; + if (UseCompressedOops || UseCompressedKlassPointers) return range - 1; return range; } --- old/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp 2012-10-08 20:35:47.821094768 +0200 +++ new/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp 2012-10-08 20:35:47.624138895 +0200 @@ -340,7 +340,7 @@ Register receiver = FrameMap::receiver_opr->as_register(); Register ic_klass = IC_Klass; const int ic_cmp_size = LP64_ONLY(10) NOT_LP64(9); - const bool do_post_padding = VerifyOops || UseCompressedOops; + const bool do_post_padding = VerifyOops || UseCompressedKlassPointers; if (!do_post_padding) { // insert some nops so that the verified entry point is aligned on CodeEntryAlignment while ((__ offset() + ic_cmp_size) % CodeEntryAlignment != 0) { @@ -1262,7 +1262,11 @@ break; case T_ADDRESS: - __ movptr(dest->as_register(), from_addr); + if (UseCompressedKlassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { + __ movl(dest->as_register(), from_addr); + } else { + __ movptr(dest->as_register(), from_addr); + } break; case T_INT: __ movl(dest->as_register(), from_addr); @@ -1364,6 +1368,8 @@ } #endif __ verify_oop(dest->as_register()); + } else if (type == T_ADDRESS && UseCompressedKlassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { + __ decode_klass_not_null(dest->as_register()); } } @@ -1705,7 +1711,7 @@ } else if (obj == klass_RInfo) { klass_RInfo = dst; } - if (k->is_loaded() && !UseCompressedOops) { + if (k->is_loaded() && !UseCompressedKlassPointers) { select_different_registers(obj, dst, k_RInfo, klass_RInfo); } else { Rtmp1 = op->tmp3()->as_register(); @@ -3446,7 +3452,7 @@ __ mov_metadata(tmp, default_type->constant_encoding()); #ifdef _LP64 if (UseCompressedKlassPointers) { - __ encode_heap_oop(tmp); + __ encode_klass_not_null(tmp); } #endif --- old/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp 2012-10-08 20:35:49.377752073 +0200 +++ new/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp 2012-10-08 20:35:49.159114293 +0200 @@ -1166,7 +1166,7 @@ } LIR_Opr reg = rlock_result(x); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedOops) { + if (!x->klass()->is_loaded() || UseCompressedKlassPointers) { tmp3 = new_register(objectType); } __ checkcast(reg, obj.result(), x->klass(), @@ -1188,7 +1188,7 @@ } obj.load_item(); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedOops) { + if (!x->klass()->is_loaded() || UseCompressedKlassPointers) { tmp3 = new_register(objectType); } __ instanceof(reg, obj.result(), x->klass(), --- old/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp 2012-10-08 20:35:50.806046660 +0200 +++ new/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp 2012-10-08 20:35:50.617107402 +0200 @@ -159,7 +159,7 @@ #ifdef _LP64 if (UseCompressedKlassPointers) { // Take care not to kill klass movptr(t1, klass); - encode_heap_oop_not_null(t1); + encode_klass_not_null(t1); movl(Address(obj, oopDesc::klass_offset_in_bytes()), t1); } else #endif --- old/src/cpu/x86/vm/vtableStubs_x86_64.cpp 2012-10-08 20:35:52.159267129 +0200 +++ new/src/cpu/x86/vm/vtableStubs_x86_64.cpp 2012-10-08 20:35:51.982641268 +0200 @@ -212,11 +212,11 @@ if (is_vtable_stub) { // Vtable stub size return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) + - (UseCompressedOops ? 16 : 0); // 1 leaq can be 3 bytes + 1 long + (UseCompressedKlassPointers ? 16 : 0); // 1 leaq can be 3 bytes + 1 long } else { // Itable stub size return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) + - (UseCompressedOops ? 32 : 0); // 2 leaqs + (UseCompressedKlassPointers ? 32 : 0); // 2 leaqs } // In order to tune these parameters, run the JVM with VM options // +PrintMiscellaneous and +WizardMode to see information about --- old/src/cpu/x86/vm/x86_32.ad 2012-10-08 20:35:53.661569815 +0200 +++ new/src/cpu/x86/vm/x86_32.ad 2012-10-08 20:35:53.385804735 +0200 @@ -1424,6 +1424,11 @@ return true; } +bool Matcher::narrow_klass_use_complex_address() { + ShouldNotCallThis(); + return true; +} + // Is it better to copy float constants, or load them directly from memory? // Intel can load a float constant from a direct address, requiring no --- old/src/cpu/x86/vm/x86_64.ad 2012-10-08 20:35:55.732897575 +0200 +++ new/src/cpu/x86/vm/x86_64.ad 2012-10-08 20:35:55.468054941 +0200 @@ -1409,10 +1409,10 @@ #ifndef PRODUCT void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - if (UseCompressedOops) { + if (UseCompressedKlassPointers) { st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - if (Universe::narrow_oop_shift() != 0) { - st->print_cr("\tdecode_heap_oop_not_null rscratch1, rscratch1"); + if (Universe::narrow_klass_shift() != 0) { + st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); } st->print_cr("\tcmpq rax, rscratch1\t # Inline cache check"); } else { @@ -1428,7 +1428,7 @@ { MacroAssembler masm(&cbuf); uint insts_size = cbuf.insts_size(); - if (UseCompressedOops) { + if (UseCompressedKlassPointers) { masm.load_klass(rscratch1, j_rarg0); masm.cmpptr(rax, rscratch1); } else { @@ -1576,6 +1576,11 @@ return (LogMinObjAlignmentInBytes <= 3); } +bool Matcher::narrow_klass_use_complex_address() { + assert(UseCompressedKlassPointers, "only for compressed klass code"); + return (LogKlassAlignmentInBytes <= 3); +} + // Is it better to copy float constants, or load them directly from // memory? Intel can load a float constant from a direct address, // requiring no extra registers. Most RISCs will have to materialize @@ -3139,6 +3144,14 @@ interface(CONST_INTER); %} +operand immNKlass() %{ + match(ConNKlass); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + // NULL Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); @@ -4038,6 +4051,145 @@ %} %} +operand indirectNarrowKlass(rRegN reg) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(DecodeNKlass reg); + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp(0x0); + %} +%} + +operand indOffset8NarrowKlass(rRegN reg, immL8 off) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeNKlass reg) off); + + format %{ "[$reg + $off (8-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +operand indOffset32NarrowKlass(rRegN reg, immL32 off) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeNKlass reg) off); + + format %{ "[$reg + $off (32-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +operand indIndexOffsetNarrowKlass(rRegN reg, rRegL lreg, immL32 off) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeNKlass reg) lreg) off); + + op_cost(10); + format %{"[$reg + $off + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp($off); + %} +%} + +operand indIndexNarrowKlass(rRegN reg, rRegL lreg) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeNKlass reg) lreg); + + op_cost(10); + format %{"[$reg + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp(0x0); + %} +%} + +operand indIndexScaleNarrowKlass(rRegN reg, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeNKlass reg) (LShiftL lreg scale)); + + op_cost(10); + format %{"[$reg + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp(0x0); + %} +%} + +operand indIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeNKlass reg) (LShiftL lreg scale)) off); + + op_cost(10); + format %{"[$reg + $off + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp($off); + %} +%} + +operand indCompressedKlassOffset(rRegN reg, immL32 off) %{ + predicate(UseCompressedKlassPointers && (Universe::narrow_klass_shift() == Address::times_8)); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeNKlass reg) off); + + op_cost(10); + format %{"[R12 + $reg << 3 + $off] (compressed klass addressing)" %} + interface(MEMORY_INTER) %{ + base(0xc); // R12 + index($reg); + scale(0x3); + disp($off); + %} +%} + +operand indPosIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(Universe::narrow_klass_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeNKlass reg) (LShiftL (ConvI2L idx) scale)) off); + + op_cost(10); + format %{"[$reg + $off + $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp($off); + %} +%} //----------Special Memory Operands-------------------------------------------- // Stack Slot Operand - This operand is used for loading and storing temporary @@ -4209,7 +4361,11 @@ indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, - indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); + indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow, + indCompressedKlassOffset, + indirectNarrowKlass, indOffset8NarrowKlass, indOffset32NarrowKlass, + indIndexOffsetNarrowKlass, indIndexNarrowKlass, indIndexScaleNarrowKlass, + indIndexScaleOffsetNarrowKlass, indPosIndexScaleOffsetNarrowKlass); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -5469,6 +5625,22 @@ ins_pipe(ialu_reg_fat); // XXX %} +instruct loadConNKlass(rRegN dst, immNKlass src) %{ + match(Set dst src); + + ins_cost(125); + format %{ "movl $dst, $src\t# compressed klass ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == NULL) { + ShouldNotReachHere(); + } else { + __ set_narrow_klass($dst$$Register, (Klass*)$src$$constant); + } + %} + ins_pipe(ialu_reg_fat); // XXX +%} + instruct loadConF0(regF dst, immF0 src) %{ match(Set dst src); @@ -5738,7 +5910,7 @@ instruct storeImmP0(memory mem, immP0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreP mem zero)); ins_cost(125); // XXX @@ -5774,9 +5946,21 @@ ins_pipe(ialu_mem_reg); %} +instruct storeNKlass(memory mem, rRegN src) +%{ + match(Set mem (StoreNKlass mem src)); + + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ movl($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmN0(memory mem, immN0 zero) %{ - predicate(Universe::narrow_oop_base() == NULL); + predicate(Universe::narrow_oop_base() == NULL && Universe::narrow_klass_base() == NULL); match(Set mem (StoreN mem zero)); ins_cost(125); // XXX @@ -5804,10 +5988,22 @@ ins_pipe(ialu_mem_imm); %} +instruct storeImmNKlass(memory mem, immNKlass src) +%{ + match(Set mem (StoreNKlass mem src)); + + ins_cost(150); // XXX + format %{ "movl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ set_narrow_klass($mem$$Address, (Klass*)$src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + // Store Integer Immediate instruct storeImmI0(memory mem, immI0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreI mem zero)); ins_cost(125); // XXX @@ -5832,7 +6028,7 @@ // Store Long Immediate instruct storeImmL0(memory mem, immL0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreL mem zero)); ins_cost(125); // XXX @@ -5857,7 +6053,7 @@ // Store Short/Char Immediate instruct storeImmC0(memory mem, immI0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreC mem zero)); ins_cost(125); // XXX @@ -5883,7 +6079,7 @@ // Store Byte Immediate instruct storeImmB0(memory mem, immI0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreB mem zero)); ins_cost(125); // XXX @@ -5908,7 +6104,7 @@ // Store CMS card-mark Immediate instruct storeImmCM0_reg(memory mem, immI0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreCM mem zero)); ins_cost(125); // XXX @@ -5946,7 +6142,7 @@ // Store immediate Float value (it is faster than store from XMM register) instruct storeF0(memory mem, immF0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreF mem zero)); ins_cost(25); // XXX @@ -5996,7 +6192,7 @@ instruct storeD0(memory mem, immD0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set mem (StoreD mem zero)); ins_cost(25); // XXX @@ -6482,6 +6678,32 @@ ins_pipe(ialu_reg_long); %} +instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ + match(Set dst (EncodePKlass src)); + effect(KILL cr); + format %{ "encode_heap_oop_not_null $dst,$src" %} + ins_encode %{ + __ encode_klass_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_long); +%} + +instruct decodeKlass_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ + match(Set dst (DecodeNKlass src)); + effect(KILL cr); + format %{ "decode_heap_oop_not_null $dst,$src" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + if (s != d) { + __ decode_klass_not_null(d, s); + } else { + __ decode_klass_not_null(d); + } + %} + ins_pipe(ialu_reg_long); +%} + //----------Conditional Move--------------------------------------------------- // Jump @@ -10452,7 +10674,7 @@ instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); match(Set cr (CmpP (LoadP mem) zero)); format %{ "cmpq R12, $mem\t# ptr (R12_heapbase==0)" %} @@ -10503,6 +10725,27 @@ ins_pipe(ialu_cr_reg_mem); %} +instruct compN_rReg_imm_klass(rFlagsRegU cr, rRegN op1, immNKlass op2) %{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed klass ptr" %} + ins_encode %{ + __ cmp_narrow_klass($op1$$Register, (Klass*)$op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compN_mem_imm_klass(rFlagsRegU cr, memory mem, immNKlass src) +%{ + match(Set cr (CmpN src (LoadNKlass mem))); + + format %{ "cmpl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ cmp_narrow_klass($mem$$Address, (Klass*)$src$$constant); + %} + ins_pipe(ialu_cr_reg_mem); +%} + instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ match(Set cr (CmpN src zero)); @@ -10526,7 +10769,7 @@ instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(Universe::narrow_oop_base() == NULL); + predicate(Universe::narrow_oop_base() == NULL && (Universe::narrow_klass_base() == NULL)); match(Set cr (CmpN (LoadN mem) zero)); format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} --- old/src/os/bsd/dtrace/generateJvmOffsets.cpp 2012-10-08 20:35:57.796881980 +0200 +++ new/src/os/bsd/dtrace/generateJvmOffsets.cpp 2012-10-08 20:35:57.609281546 +0200 @@ -267,8 +267,8 @@ printf("\n"); - GEN_OFFS(NarrowOopStruct, _base); - GEN_OFFS(NarrowOopStruct, _shift); + GEN_OFFS(NarrowPtrStruct, _base); + GEN_OFFS(NarrowPtrStruct, _shift); printf("\n"); GEN_VALUE(SIZE_HeapBlockHeader, (int) sizeof(HeapBlock::Header)); --- old/src/os/bsd/dtrace/jhelper.d 2012-10-08 20:35:59.101516892 +0200 +++ new/src/os/bsd/dtrace/jhelper.d 2012-10-08 20:35:58.916601885 +0200 @@ -45,10 +45,6 @@ extern pointer __1cJCodeCacheF_heap_; extern pointer __1cIUniverseO_collectedHeap_; -extern pointer __1cIUniverseL_narrow_oop_; -#ifdef _LP64 -extern pointer UseCompressedOops; -#endif extern pointer __1cHnmethodG__vtbl_; extern pointer __1cNMethodG__vtbl_; @@ -136,8 +132,8 @@ copyin_offset(SIZE_oopDesc); copyin_offset(SIZE_ConstantPool); - copyin_offset(OFFSET_NarrowOopStruct_base); - copyin_offset(OFFSET_NarrowOopStruct_shift); + copyin_offset(OFFSET_NarrowPtrStruct_base); + copyin_offset(OFFSET_NarrowPtrStruct_shift); /* * The PC to translate is in arg0. @@ -159,17 +155,6 @@ this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_); /* Reading volatile values */ -#ifdef _LP64 - this->Use_Compressed_Oops = copyin_uint8(&``UseCompressedOops); -#else - this->Use_Compressed_Oops = 0; -#endif - - this->Universe_narrow_oop_base = copyin_ptr(&``__1cIUniverseL_narrow_oop_ + - OFFSET_NarrowOopStruct_base); - this->Universe_narrow_oop_shift = copyin_int32(&``__1cIUniverseL_narrow_oop_ + - OFFSET_NarrowOopStruct_shift); - this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); --- old/src/os/solaris/dtrace/generateJvmOffsets.cpp 2012-10-08 20:36:00.572610790 +0200 +++ new/src/os/solaris/dtrace/generateJvmOffsets.cpp 2012-10-08 20:36:00.393603875 +0200 @@ -262,8 +262,8 @@ printf("\n"); - GEN_OFFS(NarrowOopStruct, _base); - GEN_OFFS(NarrowOopStruct, _shift); + GEN_OFFS(NarrowPtrStruct, _base); + GEN_OFFS(NarrowPtrStruct, _shift); printf("\n"); GEN_VALUE(SIZE_HeapBlockHeader, sizeof(HeapBlock::Header)); --- old/src/os/solaris/dtrace/jhelper.d 2012-10-08 20:36:01.882800131 +0200 +++ new/src/os/solaris/dtrace/jhelper.d 2012-10-08 20:36:01.702498528 +0200 @@ -45,10 +45,6 @@ extern pointer __1cJCodeCacheF_heap_; extern pointer __1cIUniverseO_collectedHeap_; -extern pointer __1cIUniverseL_narrow_oop_; -#ifdef _LP64 -extern pointer UseCompressedOops; -#endif extern pointer __1cHnmethodG__vtbl_; extern pointer __1cGMethodG__vtbl_; @@ -136,8 +132,8 @@ copyin_offset(SIZE_oopDesc); copyin_offset(SIZE_ConstantPool); - copyin_offset(OFFSET_NarrowOopStruct_base); - copyin_offset(OFFSET_NarrowOopStruct_shift); + copyin_offset(OFFSET_NarrowPtrStruct_base); + copyin_offset(OFFSET_NarrowPtrStruct_shift); /* * The PC to translate is in arg0. @@ -158,18 +154,6 @@ this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_); - /* Reading volatile values */ -#ifdef _LP64 - this->Use_Compressed_Oops = copyin_uint8(&``UseCompressedOops); -#else - this->Use_Compressed_Oops = 0; -#endif - - this->Universe_narrow_oop_base = copyin_ptr(&``__1cIUniverseL_narrow_oop_ + - OFFSET_NarrowOopStruct_base); - this->Universe_narrow_oop_shift = copyin_int32(&``__1cIUniverseL_narrow_oop_ + - OFFSET_NarrowOopStruct_shift); - this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); --- old/src/share/vm/adlc/archDesc.cpp 2012-10-08 20:36:03.730180458 +0200 +++ new/src/share/vm/adlc/archDesc.cpp 2012-10-08 20:36:03.533933463 +0200 @@ -968,7 +968,8 @@ // Create InstructForm and assign type for each ideal instruction. for ( int j = _last_machine_leaf+1; j < _last_opcode; ++j) { char *ident = (char *)NodeClassNames[j]; - if(!strcmp(ident, "ConI") || !strcmp(ident, "ConP") || !strcmp(ident, "ConN") || + if(!strcmp(ident, "ConI") || !strcmp(ident, "ConP") || + !strcmp(ident, "ConN") || !strcmp(ident, "ConNKlass") || !strcmp(ident, "ConF") || !strcmp(ident, "ConD") || !strcmp(ident, "ConL") || !strcmp(ident, "Con" ) || !strcmp(ident, "Bool") ) { --- old/src/share/vm/adlc/forms.cpp 2012-10-08 20:36:05.164092190 +0200 +++ new/src/share/vm/adlc/forms.cpp 2012-10-08 20:36:04.971081483 +0200 @@ -215,6 +215,7 @@ if (strcmp(name,"ConI")==0) return Form::idealI; if (strcmp(name,"ConP")==0) return Form::idealP; if (strcmp(name,"ConN")==0) return Form::idealN; + if (strcmp(name,"ConNKlass")==0) return Form::idealNKlass; if (strcmp(name,"ConL")==0) return Form::idealL; if (strcmp(name,"ConF")==0) return Form::idealF; if (strcmp(name,"ConD")==0) return Form::idealD; @@ -257,7 +258,7 @@ if( strcmp(opType,"LoadI")==0 ) return Form::idealI; if( strcmp(opType,"LoadUI2L")==0 ) return Form::idealI; if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP; - if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealN; + if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealNKlass; 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; @@ -280,6 +281,7 @@ if( strcmp(opType,"StoreL")==0) return Form::idealL; if( strcmp(opType,"StoreP")==0) return Form::idealP; if( strcmp(opType,"StoreN")==0) return Form::idealN; + if( strcmp(opType,"StoreNKlass")==0) return Form::idealNKlass; if( strcmp(opType,"StoreVector")==0 ) return Form::idealV; assert( strcmp(opType,"Store") != 0, "Must type Stores" ); return Form::none; --- old/src/share/vm/adlc/forms.hpp 2012-10-08 20:36:06.553438724 +0200 +++ new/src/share/vm/adlc/forms.hpp 2012-10-08 20:36:06.372483567 +0200 @@ -173,7 +173,8 @@ idealC = 7, // Char type idealS = 8, // String type idealN = 9, // Narrow oop types - idealV = 10 // Vector type + idealNKlass = 10, // Narrow klass types + idealV = 11 // Vector type }; // Convert ideal name to a DataType, return DataType::none if not a 'ConX' Form::DataType ideal_to_const_type(const char *ideal_type_name) const; --- old/src/share/vm/adlc/formssel.cpp 2012-10-08 20:36:07.803837829 +0200 +++ new/src/share/vm/adlc/formssel.cpp 2012-10-08 20:36:07.599505564 +0200 @@ -746,14 +746,16 @@ // Expected use is for pointer vs oop determination for LoadP bool InstructForm::captures_bottom_type(FormDict &globals) const { if( _matrule && _matrule->_rChild && - (!strcmp(_matrule->_rChild->_opType,"CastPP") || // new result type - !strcmp(_matrule->_rChild->_opType,"CastX2P") || // new result type - !strcmp(_matrule->_rChild->_opType,"DecodeN") || - !strcmp(_matrule->_rChild->_opType,"EncodeP") || - !strcmp(_matrule->_rChild->_opType,"LoadN") || - !strcmp(_matrule->_rChild->_opType,"GetAndSetN") || - !strcmp(_matrule->_rChild->_opType,"LoadNKlass") || - !strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception + (!strcmp(_matrule->_rChild->_opType,"CastPP") || // new result type + !strcmp(_matrule->_rChild->_opType,"CastX2P") || // new result type + !strcmp(_matrule->_rChild->_opType,"DecodeN") || + !strcmp(_matrule->_rChild->_opType,"EncodeP") || + !strcmp(_matrule->_rChild->_opType,"DecodeNKlass") || + !strcmp(_matrule->_rChild->_opType,"EncodePKlass") || + !strcmp(_matrule->_rChild->_opType,"LoadN") || + !strcmp(_matrule->_rChild->_opType,"GetAndSetN") || + !strcmp(_matrule->_rChild->_opType,"LoadNKlass") || + !strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception !strcmp(_matrule->_rChild->_opType,"CheckCastPP")) ) return true; else if ( is_ideal_load() == Form::idealP ) return true; else if ( is_ideal_store() != Form::none ) return true; @@ -2452,6 +2454,7 @@ switch(const_type) { case Form::idealI: fprintf(fp,"st->print(\"#%%d\", _c%d);\n", const_index); break; case Form::idealP: fprintf(fp,"_c%d->dump_on(st);\n", const_index); break; + case Form::idealNKlass: case Form::idealN: fprintf(fp,"_c%d->dump_on(st);\n", const_index); break; case Form::idealL: fprintf(fp,"st->print(\"#%%lld\", _c%d);\n", const_index); break; case Form::idealF: fprintf(fp,"st->print(\"#%%f\", _c%d);\n", const_index); break; @@ -3390,7 +3393,7 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { static const char *needs_ideal_memory_list[] = { - "StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" , + "StoreI","StoreL","StoreP","StoreN","StoreNKlass","StoreD","StoreF" , "StoreB","StoreC","Store" ,"StoreFP", "LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" , "LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" , @@ -3947,6 +3950,8 @@ strcmp(opType,"ConvL2I")==0 || strcmp(opType,"DecodeN")==0 || strcmp(opType,"EncodeP")==0 || + strcmp(opType,"EncodePKlass")==0 || + strcmp(opType,"DecodeNKlass")==0 || strcmp(opType,"RoundDouble")==0 || strcmp(opType,"RoundFloat")==0 || strcmp(opType,"ReverseBytesI")==0 || --- old/src/share/vm/adlc/output_c.cpp 2012-10-08 20:36:09.312551703 +0200 +++ new/src/share/vm/adlc/output_c.cpp 2012-10-08 20:36:09.098909592 +0200 @@ -3644,6 +3644,8 @@ fprintf(fp, "_leaf->bottom_type()->is_ptr()"); } else if ( (strcmp(optype,"ConN") == 0) ) { fprintf(fp, "_leaf->bottom_type()->is_narrowoop()"); + } else if ( (strcmp(optype,"ConNKlass") == 0) ) { + fprintf(fp, "_leaf->bottom_type()->is_narrowklass()"); } else if ( (strcmp(optype,"ConF") == 0) ) { fprintf(fp, "_leaf->getf()"); } else if ( (strcmp(optype,"ConD") == 0) ) { --- old/src/share/vm/adlc/output_h.cpp 2012-10-08 20:36:10.745861386 +0200 +++ new/src/share/vm/adlc/output_h.cpp 2012-10-08 20:36:10.551402597 +0200 @@ -207,6 +207,10 @@ if (i > 0) fprintf(fp,", "); fprintf(fp," const TypeNarrowOop *_c%d;\n", i); } + else if (!strcmp(type, "ConNKlass")) { + if (i > 0) fprintf(fp,", "); + fprintf(fp," const TypeNarrowKlass *_c%d;\n", i); + } else if (!strcmp(type, "ConL")) { if (i > 0) fprintf(fp,", "); fprintf(fp," jlong _c%d;\n", i); @@ -243,6 +247,10 @@ fprintf(fp," const TypePtr *_c%d;\n", i); i++; } + else if (!strcmp(comp->base_type(globals), "ConNKlass")) { + fprintf(fp," const TypePtr *_c%d;\n", i); + i++; + } else if (!strcmp(comp->base_type(globals), "ConL")) { fprintf(fp," jlong _c%d;\n", i); i++; @@ -288,11 +296,12 @@ fprintf(fp,is_ideal_bool ? "BoolTest::mask c%d" : "int32 c%d", i); break; } - case Form::idealN : { fprintf(fp,"const TypeNarrowOop *c%d", i); break; } - case Form::idealP : { fprintf(fp,"const TypePtr *c%d", i); break; } - case Form::idealL : { fprintf(fp,"jlong c%d", i); break; } - case Form::idealF : { fprintf(fp,"jfloat c%d", i); break; } - case Form::idealD : { fprintf(fp,"jdouble c%d", i); break; } + case Form::idealN : { fprintf(fp,"const TypeNarrowOop *c%d", i); break; } + case Form::idealNKlass : { fprintf(fp,"const TypeNarrowKlass *c%d", i); break; } + case Form::idealP : { fprintf(fp,"const TypePtr *c%d", i); break; } + case Form::idealL : { fprintf(fp,"jlong c%d", i); break; } + case Form::idealF : { fprintf(fp,"jfloat c%d", i); break; } + case Form::idealD : { fprintf(fp,"jdouble c%d", i); break; } default: assert(!is_ideal_bool, "Non-constant operand lacks component list."); break; @@ -316,6 +325,11 @@ fprintf(fp,"const TypePtr *c%d", i); i++; } + else if (!strcmp(comp->base_type(globals), "ConNKlass")) { + if (i > 0) fprintf(fp,", "); + fprintf(fp,"const TypePtr *c%d", i); + i++; + } else if (!strcmp(comp->base_type(globals), "ConL")) { if (i > 0) fprintf(fp,", "); fprintf(fp,"jlong c%d", i); @@ -380,6 +394,10 @@ fprintf(fp," _c%d->dump_on(st);\n", i); ++i; } + else if (!strcmp(ideal_type, "ConNKlass")) { + fprintf(fp," _c%d->dump_on(st);\n", i); + ++i; + } else if (!strcmp(ideal_type, "ConL")) { fprintf(fp," st->print(\"#\" INT64_FORMAT, _c%d);\n", i); ++i; @@ -1239,7 +1257,7 @@ if( type != NULL ) { Form::DataType data_type = oper->is_base_constant(_globalNames); // Check if we are an ideal pointer type - if( data_type == Form::idealP || data_type == Form::idealN ) { + if( data_type == Form::idealP || data_type == Form::idealN || data_type == Form::idealNKlass ) { // Return the ideal type we already have: fprintf(fp," return _c0;"); } else { @@ -1377,6 +1395,16 @@ fprintf(fp, " return _c0->get_ptrtype()->reloc();"); fprintf(fp, " }\n"); } + else if (!strcmp(oper->ideal_type(_globalNames), "ConNKlass")) { + // Access the locally stored constant + fprintf(fp," virtual intptr_t constant() const {"); + fprintf(fp, " return _c0->get_ptrtype()->get_con();"); + fprintf(fp, " }\n"); + // Generate query to determine if this pointer is an oop + fprintf(fp," virtual relocInfo::relocType constant_reloc() const {"); + fprintf(fp, " return _c0->get_ptrtype()->reloc();"); + fprintf(fp, " }\n"); + } else if (!strcmp(oper->ideal_type(_globalNames), "ConL")) { fprintf(fp," virtual intptr_t constant() const {"); // We don't support addressing modes with > 4Gig offsets. @@ -1810,6 +1838,7 @@ break; case Form::idealP: case Form::idealN: + case Form::idealNKlass: fprintf(fp," return opnd_array(1)->type();\n"); break; case Form::idealD: --- old/src/share/vm/c1/c1_LIRGenerator.cpp 2012-10-08 20:36:12.256161651 +0200 +++ new/src/share/vm/c1/c1_LIRGenerator.cpp 2012-10-08 20:36:12.041858670 +0200 @@ -1286,7 +1286,7 @@ if (x->needs_null_check()) { info = state_for(x); } - __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), UseCompressedKlassPointers ? T_OBJECT : T_ADDRESS), result, info); + __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), result, info); __ move_wide(new LIR_Address(result, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result); } --- old/src/share/vm/ci/ciObjectFactory.cpp 2012-10-08 20:36:13.858649541 +0200 +++ new/src/share/vm/ci/ciObjectFactory.cpp 2012-10-08 20:36:13.620920534 +0200 @@ -146,7 +146,7 @@ for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) { BasicType t = (BasicType)i; - if (type2name(t) != NULL && t != T_OBJECT && t != T_ARRAY && t != T_NARROWOOP) { + if (type2name(t) != NULL && t != T_OBJECT && t != T_ARRAY && t != T_NARROWOOP && t != T_NARROWKLASS) { ciType::_basic_types[t] = new (_arena) ciType(t); init_ident_of(ciType::_basic_types[t]); } --- old/src/share/vm/classfile/classFileParser.cpp 2012-10-08 20:36:15.193740091 +0200 +++ new/src/share/vm/classfile/classFileParser.cpp 2012-10-08 20:36:14.981814055 +0200 @@ -1008,40 +1008,42 @@ BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 - NONSTATIC_BYTE , // T_BOOLEAN = 4, - NONSTATIC_SHORT, // T_CHAR = 5, - NONSTATIC_WORD, // T_FLOAT = 6, - NONSTATIC_DOUBLE, // T_DOUBLE = 7, - NONSTATIC_BYTE, // T_BYTE = 8, - NONSTATIC_SHORT, // T_SHORT = 9, - NONSTATIC_WORD, // T_INT = 10, - NONSTATIC_DOUBLE, // T_LONG = 11, - NONSTATIC_OOP, // T_OBJECT = 12, - NONSTATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP= 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 18, + NONSTATIC_BYTE , // T_BOOLEAN = 4, + NONSTATIC_SHORT, // T_CHAR = 5, + NONSTATIC_WORD, // T_FLOAT = 6, + NONSTATIC_DOUBLE, // T_DOUBLE = 7, + NONSTATIC_BYTE, // T_BYTE = 8, + NONSTATIC_SHORT, // T_SHORT = 9, + NONSTATIC_WORD, // T_INT = 10, + NONSTATIC_DOUBLE, // T_LONG = 11, + NONSTATIC_OOP, // T_OBJECT = 12, + NONSTATIC_OOP, // T_ARRAY = 13, + BAD_ALLOCATION_TYPE, // T_VOID = 14, + BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, + BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, + BAD_ALLOCATION_TYPE, // T_METADATA = 17, + BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, + BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, BAD_ALLOCATION_TYPE, // 0 BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 - STATIC_BYTE , // T_BOOLEAN = 4, - STATIC_SHORT, // T_CHAR = 5, - STATIC_WORD, // T_FLOAT = 6, - STATIC_DOUBLE, // T_DOUBLE = 7, - STATIC_BYTE, // T_BYTE = 8, - STATIC_SHORT, // T_SHORT = 9, - STATIC_WORD, // T_INT = 10, - STATIC_DOUBLE, // T_LONG = 11, - STATIC_OOP, // T_OBJECT = 12, - STATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP= 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 18, + STATIC_BYTE , // T_BOOLEAN = 4, + STATIC_SHORT, // T_CHAR = 5, + STATIC_WORD, // T_FLOAT = 6, + STATIC_DOUBLE, // T_DOUBLE = 7, + STATIC_BYTE, // T_BYTE = 8, + STATIC_SHORT, // T_SHORT = 9, + STATIC_WORD, // T_INT = 10, + STATIC_DOUBLE, // T_LONG = 11, + STATIC_OOP, // T_OBJECT = 12, + STATIC_OOP, // T_ARRAY = 13, + BAD_ALLOCATION_TYPE, // T_VOID = 14, + BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, + BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, + BAD_ALLOCATION_TYPE, // T_METADATA = 17, + BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, + BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, }; static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) { --- old/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp 2012-10-08 20:36:17.101288394 +0200 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp 2012-10-08 20:36:16.808011949 +0200 @@ -222,7 +222,7 @@ // depends on this property. debug_only( FreeChunk* junk = NULL; - assert(UseCompressedOops || + assert(UseCompressedKlassPointers || junk->prev_addr() == (void*)(oop(junk)->klass_addr()), "Offset of FreeChunk::_prev within FreeChunk must match" " that of OopDesc::_klass within OopDesc"); --- old/src/share/vm/memory/metaspace.hpp 2012-10-08 20:36:18.881704337 +0200 +++ new/src/share/vm/memory/metaspace.hpp 2012-10-08 20:36:18.699845368 +0200 @@ -135,6 +135,8 @@ MetaWord* expand_and_allocate(size_t size, MetadataType mdtype); + static bool is_initialized() { return _class_space_list != NULL; } + #ifndef PRODUCT bool contains(const void *ptr) const; bool contains_class(const void *ptr) const; --- old/src/share/vm/memory/universe.cpp 2012-10-08 20:36:20.339439327 +0200 +++ new/src/share/vm/memory/universe.cpp 2012-10-08 20:36:20.116424467 +0200 @@ -151,7 +151,9 @@ CollectedHeap* Universe::_collectedHeap = NULL; -NarrowOopStruct Universe::_narrow_oop = { NULL, 0, true }; +NarrowPtrStruct Universe::_narrow_oop = { NULL, 0, true }; +NarrowPtrStruct Universe::_narrow_klass = { NULL, 0, true }; +address Universe::_narrow_ptrs_base; void Universe::basic_type_classes_do(void f(Klass*)) { @@ -807,7 +809,7 @@ } if ((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) { // Can't reserve heap below 32Gb. - Universe::set_narrow_oop_base(Universe::heap()->base() - os::vm_page_size()); + // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); if (verbose) { tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base()); @@ -838,8 +840,16 @@ tty->cr(); tty->cr(); } - } - assert(Universe::narrow_oop_base() == (Universe::heap()->base() - os::vm_page_size()) || + if (UseCompressedKlassPointers) { + Universe::set_narrow_klass_base(Universe::narrow_oop_base()); + Universe::set_narrow_klass_shift(MIN2(Universe::narrow_oop_shift(), LogKlassAlignmentInBytes)); + } + Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); + } + // Universe::narrow_oop_base() is one page below the metaspace + // base. The actual metaspace base depends on alignment constraints + // so we don't know its exact location here. + assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - os::vm_page_size() - ClassMetaspaceSize) || Universe::narrow_oop_base() == NULL, "invalid value"); assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes || Universe::narrow_oop_shift() == 0, "invalid value"); @@ -861,7 +871,10 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { // Add in the class metaspace area so the classes in the headers can // be compressed the same as instances. - size_t total_reserved = align_size_up(heap_size + ClassMetaspaceSize, alignment); + // Need to round class space size up because it's below the heap and + // the actual alignment depends on its size. + size_t metaspace_size = align_size_up(ClassMetaspaceSize, alignment); + size_t total_reserved = align_size_up(heap_size + metaspace_size, alignment); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); @@ -895,11 +908,23 @@ return total_rs; } - // Split the reserved space into main Java heap and a space for classes - // so that they can be compressed using the same algorithm as compressed oops - ReservedSpace heap_rs = total_rs.first_part(heap_size); - ReservedSpace class_rs = total_rs.last_part(heap_size, alignment); + // Split the reserved space into main Java heap and a space for + // classes so that they can be compressed using the same algorithm + // as compressed oops. If compress oops and compress klass ptrs are + // used we need the meta space first: if the alignment used for + // compressed oops is greater than the one used for compressed klass + // ptrs, a metadata space on top of the heap could become + // unreachable. + ReservedSpace class_rs = total_rs.first_part(metaspace_size); + ReservedSpace heap_rs = total_rs.last_part(metaspace_size, alignment); Metaspace::initialize_class_space(class_rs); + + if (UseCompressedOops) { + // Universe::initialize_heap() will reset this to NULL if unscaled + // or zero-based narrow oops are actually used. + address base = (address)(total_rs.base() - os::vm_page_size()); + Universe::set_narrow_oop_base(base); + } return heap_rs; } --- old/src/share/vm/memory/universe.hpp 2012-10-08 20:36:21.642880873 +0200 +++ new/src/share/vm/memory/universe.hpp 2012-10-08 20:36:21.436412125 +0200 @@ -105,16 +105,16 @@ Method* get_Method(); }; -// For UseCompressedOops. -struct NarrowOopStruct { - // Base address for oop-within-java-object materialization. - // NULL if using wide oops or zero based narrow oops. +// For UseCompressedOops and UseCompressedKlassPointers. +struct NarrowPtrStruct { + // Base address for oop/klass-within-java-object materialization. + // NULL if using wide oops/klasses or zero based narrow oops/klasses. address _base; - // Number of shift bits for encoding/decoding narrow oops. - // 0 if using wide oops or zero based unscaled narrow oops, - // LogMinObjAlignmentInBytes otherwise. + // Number of shift bits for encoding/decoding narrow ptrs. + // 0 if using wide ptrs or zero based unscaled narrow ptrs, + // LogMinObjAlignmentInBytes/LogKlassAlignmentInBytes otherwise. int _shift; - // Generate code with implicit null checks for narrow oops. + // Generate code with implicit null checks for narrow ptrs. bool _use_implicit_null_checks; }; @@ -206,7 +206,10 @@ static CollectedHeap* _collectedHeap; // For UseCompressedOops. - static struct NarrowOopStruct _narrow_oop; + static struct NarrowPtrStruct _narrow_oop; + // For UseCompressedKlassPointers. + static struct NarrowPtrStruct _narrow_klass; + static address _narrow_ptrs_base; // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) @@ -259,8 +262,21 @@ HeapBasedNarrowOop = 2 }; static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); - static void set_narrow_oop_base(address base) { _narrow_oop._base = base; } - static void set_narrow_oop_use_implicit_null_checks(bool use) { _narrow_oop._use_implicit_null_checks = use; } + static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); + static void set_narrow_oop_base(address base) { + assert(UseCompressedOops, "no compressed oops?"); + _narrow_oop._base = base; + } + static void set_narrow_klass_base(address base) { + assert(UseCompressedKlassPointers, "no compressed klass ptrs?"); + _narrow_klass._base = base; + } + static void set_narrow_oop_use_implicit_null_checks(bool use) { + assert(UseCompressedOops, "no compressed ptrs?"); + _narrow_oop._use_implicit_null_checks = use; + } + static bool reserve_metaspace_helper(bool with_base = false); + static ReservedHeapSpace reserve_heap_metaspace(size_t heap_size, size_t alignment, bool& contiguous); // Debugging static int _verify_count; // number of verifies done @@ -354,14 +370,32 @@ static CollectedHeap* heap() { return _collectedHeap; } // For UseCompressedOops - static address* narrow_oop_base_addr() { return &_narrow_oop._base; } - static address narrow_oop_base() { return _narrow_oop._base; } - static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } - static int narrow_oop_shift() { return _narrow_oop._shift; } - static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; } + static address narrow_oop_base() { return _narrow_oop._base; } + static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } + static int narrow_oop_shift() { return _narrow_oop._shift; } + static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; } + + // For UseCompressedKlassPointers + static address narrow_klass_base() { return _narrow_klass._base; } + static bool is_narrow_klass_base(void* addr) { return (narrow_klass_base() == (address)addr); } + static int narrow_klass_shift() { return _narrow_klass._shift; } + static bool narrow_klass_use_implicit_null_checks() { return _narrow_klass._use_implicit_null_checks; } + + static address* narrow_ptrs_base_addr() { return &_narrow_ptrs_base; } + static void set_narrow_ptrs_base(address a) { _narrow_ptrs_base = a; } + static address narrow_ptrs_base() { return _narrow_ptrs_base; } // this is set in vm_version on sparc (and then reset in universe afaict) - static void set_narrow_oop_shift(int shift) { _narrow_oop._shift = shift; } + static void set_narrow_oop_shift(int shift) { + assert(UseCompressedOops, "no compressed oops?"); + _narrow_oop._shift = shift; + } + + static void set_narrow_klass_shift(int shift) { + assert(UseCompressedKlassPointers, "no compressed klass ptrs?"); + assert(shift == 0 || shift == LogKlassAlignmentInBytes, "invalid shift for klass ptrs"); + _narrow_klass._shift = shift; + } // Reserve Java heap and determine CompressedOops mode static ReservedSpace reserve_heap(size_t heap_size, size_t alignment); --- old/src/share/vm/oops/instanceOop.hpp 2012-10-08 20:36:22.965413364 +0200 +++ new/src/share/vm/oops/instanceOop.hpp 2012-10-08 20:36:22.779055895 +0200 @@ -37,7 +37,9 @@ // If compressed, the offset of the fields of the instance may not be aligned. static int base_offset_in_bytes() { - return UseCompressedKlassPointers ? + // offset computation code breaks if UseCompressedKlassPointers + // only is true + return (UseCompressedOops && UseCompressedKlassPointers) ? klass_gap_offset_in_bytes() : sizeof(instanceOopDesc); } --- old/src/share/vm/oops/oop.inline.hpp 2012-10-08 20:36:24.344842886 +0200 +++ new/src/share/vm/oops/oop.inline.hpp 2012-10-08 20:36:24.142490900 +0200 @@ -185,8 +185,8 @@ inline bool check_obj_alignment(oop obj) { return (intptr_t)obj % MinObjAlignmentInBytes == 0; } -inline bool check_obj_alignment(Klass* obj) { - return (intptr_t)obj % MinObjAlignmentInBytes == 0; +inline bool check_klass_alignment(Klass* obj) { + return (intptr_t)obj % KlassAlignmentInBytes == 0; } inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { @@ -228,9 +228,9 @@ inline narrowOop oopDesc::encode_klass_not_null(Klass* v) { assert(!is_null(v), "oop value can never be zero"); - assert(check_obj_alignment(v), "Address not aligned"); - address base = Universe::narrow_oop_base(); - int shift = Universe::narrow_oop_shift(); + assert(check_klass_alignment(v), "Address not aligned"); + address base = Universe::narrow_klass_base(); + int shift = Universe::narrow_klass_shift(); uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift; @@ -245,10 +245,10 @@ inline Klass* oopDesc::decode_klass_not_null(narrowOop v) { assert(!is_null(v), "narrow oop value can never be zero"); - address base = Universe::narrow_oop_base(); - int shift = Universe::narrow_oop_shift(); + address base = Universe::narrow_klass_base(); + int shift = Universe::narrow_klass_shift(); Klass* result = (Klass*)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); - assert(check_obj_alignment(result), err_msg("address not aligned: " PTR_FORMAT, (void*) result)); + assert(check_klass_alignment(result), err_msg("address not aligned: " PTR_FORMAT, (void*) result)); return result; } --- old/src/share/vm/opto/cfgnode.cpp 2012-10-08 20:36:25.809110539 +0200 +++ new/src/share/vm/opto/cfgnode.cpp 2012-10-08 20:36:25.618700756 +0200 @@ -1386,7 +1386,7 @@ Node *n = phi->in(i); if( !n ) return NULL; if( phase->type(n) == Type::TOP ) return NULL; - if( n->Opcode() == Op_ConP || n->Opcode() == Op_ConN ) + if( n->Opcode() == Op_ConP || n->Opcode() == Op_ConN || n->Opcode() == Op_ConNKlass ) break; } if( i >= phi->req() ) // Only split for constants @@ -1875,17 +1875,19 @@ } #ifdef _LP64 - // Push DecodeN down through phi. + // Push DecodeN/DecodeNKlass down through phi. // The rest of phi graph will transform by split EncodeP node though phis up. - if (UseCompressedOops && can_reshape && progress == NULL) { + if ((UseCompressedOops || UseCompressedKlassPointers) && can_reshape && progress == NULL) { bool may_push = true; bool has_decodeN = false; + bool is_decodeN = false; for (uint i=1; iis_DecodeN() && ii->bottom_type() == bottom_type()) { + if (ii->is_DecodeNarrowPtr() && ii->bottom_type() == bottom_type()) { // Do optimization if a non dead path exist. if (ii->in(1)->bottom_type() != Type::TOP) { has_decodeN = true; + is_decodeN = ii->is_DecodeN(); } } else if (!ii->is_Phi()) { may_push = false; @@ -1895,13 +1897,18 @@ if (has_decodeN && may_push) { PhaseIterGVN *igvn = phase->is_IterGVN(); // Make narrow type for new phi. - const Type* narrow_t = TypeNarrowOop::make(this->bottom_type()->is_ptr()); + const Type* narrow_t; + if (is_decodeN) { + narrow_t = TypeNarrowOop::make(this->bottom_type()->is_ptr()); + } else { + narrow_t = TypeNarrowKlass::make(this->bottom_type()->is_ptr()); + } PhiNode* new_phi = new (phase->C) PhiNode(r, narrow_t); uint orig_cnt = req(); for (uint i=1; iis_DecodeN()) { + if (ii->is_DecodeNarrowPtr()) { assert(ii->bottom_type() == bottom_type(), "sanity"); new_ii = ii->in(1); } else { @@ -1909,14 +1916,22 @@ if (ii->as_Phi() == this) { new_ii = new_phi; } else { - new_ii = new (phase->C) EncodePNode(ii, narrow_t); + if (is_decodeN) { + new_ii = new (phase->C) EncodePNode(ii, narrow_t); + } else { + new_ii = new (phase->C) EncodePKlassNode(ii, narrow_t); + } igvn->register_new_node_with_optimizer(new_ii); } } new_phi->set_req(i, new_ii); } igvn->register_new_node_with_optimizer(new_phi, this); - progress = new (phase->C) DecodeNNode(new_phi, bottom_type()); + if (is_decodeN) { + progress = new (phase->C) DecodeNNode(new_phi, bottom_type()); + } else { + progress = new (phase->C) DecodeNKlassNode(new_phi, bottom_type()); + } } } #endif --- old/src/share/vm/opto/classes.hpp 2012-10-08 20:36:27.215204068 +0200 +++ new/src/share/vm/opto/classes.hpp 2012-10-08 20:36:27.032778328 +0200 @@ -91,6 +91,7 @@ macro(GetAndSetN) macro(Con) macro(ConN) +macro(ConNKlass) macro(ConD) macro(ConF) macro(ConI) @@ -118,6 +119,7 @@ macro(CountTrailingZerosL) macro(CreateEx) macro(DecodeN) +macro(DecodeNKlass) macro(DivD) macro(DivF) macro(DivI) @@ -126,6 +128,7 @@ macro(DivModI) macro(DivModL) macro(EncodeP) +macro(EncodePKlass) macro(ExpD) macro(FastLock) macro(FastUnlock) @@ -233,6 +236,7 @@ macro(StoreL) macro(StoreP) macro(StoreN) +macro(StoreNKlass) macro(StrComp) macro(StrEquals) macro(StrIndexOf) --- old/src/share/vm/opto/compile.cpp 2012-10-08 20:36:28.565733818 +0200 +++ new/src/share/vm/opto/compile.cpp 2012-10-08 20:36:28.361288587 +0200 @@ -2236,6 +2236,7 @@ nop != Op_CreateEx && nop != Op_CheckCastPP && nop != Op_DecodeN && + nop != Op_DecodeNKlass && !n->is_Mem() ) { Node *x = n->clone(); call->set_req( TypeFunc::Parms, x ); @@ -2284,6 +2285,7 @@ case Op_GetAndSetN: case Op_StoreP: case Op_StoreN: + case Op_StoreNKlass: case Op_LoadB: case Op_LoadUB: case Op_LoadUS: @@ -2318,7 +2320,7 @@ addp->in(AddPNode::Base) == n->in(AddPNode::Base), "Base pointers must match" ); #ifdef _LP64 - if (UseCompressedOops && + if ((UseCompressedOops || UseCompressedKlassPointers) && addp->Opcode() == Op_ConP && addp == n->in(AddPNode::Base) && n->in(AddPNode::Offset)->is_Con()) { @@ -2327,16 +2329,18 @@ // 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()) { + if (t->isa_oopptr() || t->isa_klassptr()) { Node* nn = NULL; + int op = t->isa_oopptr() ? Op_ConN : Op_ConNKlass; + // 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 && + if (m!= NULL && m->Opcode() == op && m->bottom_type()->make_ptr() == t) { nn = m; break; @@ -2345,7 +2349,11 @@ if (nn != NULL) { // Decode a narrow oop to match address // [R12 + narrow_oop_reg<<3 + offset] - nn = new (C) DecodeNNode(nn, t); + if (t->isa_oopptr()) { + nn = new (C) DecodeNNode(nn, t); + } else { + nn = new (C) DecodeNKlassNode(nn, t); + } n->set_req(AddPNode::Base, nn); n->set_req(AddPNode::Address, nn); if (addp->outcnt() == 0) { @@ -2400,22 +2408,24 @@ 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() || n->in(2)->is_DecodeN()) { + if (n->in(1)->is_DecodeNarrowPtr() || n->in(2)->is_DecodeNarrowPtr()) { Node* in1 = n->in(1); Node* in2 = n->in(2); - if (!in1->is_DecodeN()) { + if (!in1->is_DecodeNarrowPtr()) { in2 = in1; in1 = n->in(2); } - assert(in1->is_DecodeN(), "sanity"); + assert(in1->is_DecodeNarrowPtr(), "sanity"); Compile* C = Compile::current(); Node* new_in2 = NULL; - if (in2->is_DecodeN()) { + if (in2->is_DecodeNarrowPtr()) { + assert(in2->Opcode() == in1->Opcode(), "must be same node type"); new_in2 = in2->in(1); } else if (in2->Opcode() == Op_ConP) { const Type* t = in2->bottom_type(); if (t == TypePtr::NULL_PTR) { + assert(in1->is_DecodeN(), "compare klass to null?"); // Don't convert CmpP null check into CmpN if compressed // oops implicit null check is not generated. // This will allow to generate normal oop implicit null check. @@ -2460,6 +2470,8 @@ // } else if (t->isa_oopptr()) { new_in2 = ConNode::make(C, t->make_narrowoop()); + } else if (t->isa_klassptr()) { + new_in2 = ConNode::make(C, t->make_narrowklass()); } } if (new_in2 != NULL) { @@ -2476,23 +2488,28 @@ break; case Op_DecodeN: - assert(!n->in(1)->is_EncodeP(), "should be optimized out"); + case Op_DecodeNKlass: + assert(!n->in(1)->is_EncodeNarrowPtr(), "should be optimized out"); // DecodeN could be pinned when it can't be fold into // an address expression, see the code for Op_CastPP above. - assert(n->in(0) == NULL || !Matcher::narrow_oop_use_complex_address(), "no control"); + assert(n->in(0) == NULL || (UseCompressedOops && !Matcher::narrow_oop_use_complex_address()), "no control"); break; - case Op_EncodeP: { + case Op_EncodeP: + case Op_EncodePKlass: { Node* in1 = n->in(1); - if (in1->is_DecodeN()) { + if (in1->is_DecodeNarrowPtr()) { n->subsume_by(in1->in(1)); } else if (in1->Opcode() == Op_ConP) { Compile* C = Compile::current(); const Type* t = in1->bottom_type(); if (t == TypePtr::NULL_PTR) { + assert(t->isa_oopptr(), "null klass?"); n->subsume_by(ConNode::make(C, TypeNarrowOop::NULL_PTR)); } else if (t->isa_oopptr()) { n->subsume_by(ConNode::make(C, t->make_narrowoop())); + } else if (t->isa_klassptr()) { + n->subsume_by(ConNode::make(C, t->make_narrowklass())); } } if (in1->outcnt() == 0) { @@ -2526,7 +2543,7 @@ } case Op_Phi: - if (n->as_Phi()->bottom_type()->isa_narrowoop()) { + if (n->as_Phi()->bottom_type()->isa_narrowoop() || n->as_Phi()->bottom_type()->isa_narrowklass()) { // The EncodeP optimization may create Phi with the same edges // for all paths. It is not handled well by Register Allocator. Node* unique_in = n->in(1); @@ -2689,12 +2706,13 @@ } // Skip next transformation if compressed oops are not used. - if (!UseCompressedOops || !Matcher::gen_narrow_oop_implicit_null_checks()) + if ((UseCompressedOops && !Matcher::gen_narrow_oop_implicit_null_checks()) || + (!UseCompressedOops && !UseCompressedKlassPointers)) return; - // Go over safepoints nodes to skip DecodeN nodes for debug edges. + // Go over safepoints nodes to skip DecodeN/DecodeNKlass nodes for debug edges. // It could be done for an uncommon traps or any safepoints/calls - // if the DecodeN node is referenced only in a debug info. + // if the DecodeN/DecodeNKlass node is referenced only in a debug info. while (sfpt.size() > 0) { n = sfpt.pop(); JVMState *jvms = n->as_SafePoint()->jvms(); @@ -2705,7 +2723,7 @@ n->as_CallStaticJava()->uncommon_trap_request() != 0); for (int j = start; j < end; j++) { Node* in = n->in(j); - if (in->is_DecodeN()) { + if (in->is_DecodeNarrowPtr()) { bool safe_to_skip = true; if (!is_uncommon ) { // Is it safe to skip? --- old/src/share/vm/opto/connode.cpp 2012-10-08 20:36:29.965920632 +0200 +++ new/src/share/vm/opto/connode.cpp 2012-10-08 20:36:29.769538702 +0200 @@ -45,16 +45,17 @@ //------------------------------make------------------------------------------- ConNode *ConNode::make( Compile* C, const Type *t ) { switch( t->basic_type() ) { - case T_INT: return new (C) ConINode( t->is_int() ); - case T_LONG: return new (C) ConLNode( t->is_long() ); - case T_FLOAT: return new (C) ConFNode( t->is_float_constant() ); - case T_DOUBLE: return new (C) ConDNode( t->is_double_constant() ); - case T_VOID: return new (C) ConNode ( Type::TOP ); - case T_OBJECT: return new (C) ConPNode( t->is_ptr() ); - case T_ARRAY: return new (C) ConPNode( t->is_aryptr() ); - case T_ADDRESS: return new (C) ConPNode( t->is_ptr() ); - case T_NARROWOOP: return new (C) ConNNode( t->is_narrowoop() ); - case T_METADATA: return new (C) ConPNode( t->is_ptr() ); + case T_INT: return new (C) ConINode( t->is_int() ); + case T_LONG: return new (C) ConLNode( t->is_long() ); + case T_FLOAT: return new (C) ConFNode( t->is_float_constant() ); + case T_DOUBLE: return new (C) ConDNode( t->is_double_constant() ); + case T_VOID: return new (C) ConNode ( Type::TOP ); + case T_OBJECT: return new (C) ConPNode( t->is_ptr() ); + case T_ARRAY: return new (C) ConPNode( t->is_aryptr() ); + case T_ADDRESS: return new (C) ConPNode( t->is_ptr() ); + case T_NARROWOOP: return new (C) ConNNode( t->is_narrowoop() ); + case T_NARROWKLASS: return new (C) ConNKlassNode( t->is_narrowklass() ); + case T_METADATA: return new (C) ConPNode( t->is_ptr() ); // 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 @@ -447,7 +448,7 @@ // If not converting int->oop, throw away cast after constant propagation Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || (in(1)->is_DecodeN() && Matcher::gen_narrow_oop_implicit_null_checks())) { + if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { return NULL; // do not transform raw pointers or narrow oops } return ConstraintCastNode::Ideal_DU_postCCP(ccp); @@ -607,15 +608,56 @@ if (t == Type::TOP) return Type::TOP; if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR; - assert(t->isa_oop_ptr() || UseCompressedKlassPointers && t->isa_klassptr(), "only oopptr here"); + assert(t->isa_oop_ptr(), "only oopptr here"); return t->make_narrowoop(); } -Node *EncodePNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { +Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); } +Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_EncodePKlass()) { + // (DecodeNKlass (EncodePKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert(t != TypeNarrowKlass::NULL_PTR, "null klass?"); + + assert(t->isa_narrowklass(), "only narrow klass ptr here"); + return t->make_ptr(); +} + +Node* EncodePKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_DecodeNKlass()) { + // (EncodePKlass (DecodeNKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert (t != TypePtr::NULL_PTR, "null klass?"); + + assert(UseCompressedKlassPointers && t->isa_klassptr(), "only klass ptr here"); + return t->make_narrowklass(); +} + + //============================================================================= //------------------------------Identity--------------------------------------- Node *Conv2BNode::Identity( PhaseTransform *phase ) { --- old/src/share/vm/opto/connode.hpp 2012-10-08 20:36:31.271945481 +0200 +++ new/src/share/vm/opto/connode.hpp 2012-10-08 20:36:31.089002406 +0200 @@ -88,6 +88,14 @@ virtual int Opcode() const; }; +//------------------------------ConNKlassNode--------------------------------- +// Simple narrow klass constants +class ConNKlassNode : public ConNode { +public: + ConNKlassNode( const TypeNarrowKlass *t ) : ConNode(t) {} + virtual int Opcode() const; +}; + //------------------------------ConLNode--------------------------------------- // Simple long constants @@ -270,42 +278,91 @@ }; +//------------------------------EncodeNarrowPtr-------------------------------- +class EncodeNarrowPtrNode : public TypeNode { + protected: + EncodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_EncodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegN; } + virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); +}; + //------------------------------EncodeP-------------------------------- // Encodes an oop pointers into its compressed form // Takes an extra argument which is the real heap base as a long which // may be useful for code generation in the backend. -class EncodePNode : public TypeNode { +class EncodePNode : public EncodeNarrowPtrNode { public: EncodePNode(Node* value, const Type* type): - TypeNode(type, 2) { + EncodeNarrowPtrNode(value, type) { init_class_id(Class_EncodeP); - init_req(0, NULL); - init_req(1, value); } virtual int Opcode() const; virtual Node *Identity( PhaseTransform *phase ); virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegN; } +}; - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); +//------------------------------EncodePKlass-------------------------------- +// Encodes a klass pointer into its compressed form +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class EncodePKlassNode : public EncodeNarrowPtrNode { + public: + EncodePKlassNode(Node* value, const Type* type): + EncodeNarrowPtrNode(value, type) { + init_class_id(Class_EncodePKlass); + } + virtual int Opcode() const; + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + +//------------------------------DecodeNarrowPtr-------------------------------- +class DecodeNarrowPtrNode : public TypeNode { + protected: + DecodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_DecodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegP; } }; //------------------------------DecodeN-------------------------------- // Converts a narrow oop into a real oop ptr. // Takes an extra argument which is the real heap base as a long which // may be useful for code generation in the backend. -class DecodeNNode : public TypeNode { +class DecodeNNode : public DecodeNarrowPtrNode { public: DecodeNNode(Node* value, const Type* type): - TypeNode(type, 2) { + DecodeNarrowPtrNode(value, type) { init_class_id(Class_DecodeN); - init_req(0, NULL); - init_req(1, value); } virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; virtual Node *Identity( PhaseTransform *phase ); +}; + +//------------------------------DecodeNKlass-------------------------------- +// Converts a narrow klass pointer into a real klass ptr. +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class DecodeNKlassNode : public DecodeNarrowPtrNode { + public: + DecodeNKlassNode(Node* value, const Type* type): + DecodeNarrowPtrNode(value, type) { + init_class_id(Class_DecodeNKlass); + } + virtual int Opcode() const; virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegP; } + virtual Node *Identity( PhaseTransform *phase ); }; //------------------------------Conv2BNode------------------------------------- --- old/src/share/vm/opto/escape.cpp 2012-10-08 20:36:32.928134504 +0200 +++ new/src/share/vm/opto/escape.cpp 2012-10-08 20:36:32.702773085 +0200 @@ -368,7 +368,9 @@ case Op_CastPP: case Op_CheckCastPP: case Op_EncodeP: - case Op_DecodeN: { + case Op_DecodeN: + case Op_EncodePKlass: + case Op_DecodeNKlass: { add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist); break; @@ -381,7 +383,8 @@ break; } case Op_ConP: - case Op_ConN: { + case Op_ConN: + case Op_ConNKlass: { // assume all oop constants globally escape except for null PointsToNode::EscapeState es; if (igvn->type(n) == TypePtr::NULL_PTR || @@ -458,6 +461,7 @@ } case Op_StoreP: case Op_StoreN: + case Op_StoreNKlass: case Op_StorePConditional: case Op_CompareAndSwapP: case Op_CompareAndSwapN: { @@ -465,7 +469,7 @@ const Type *adr_type = igvn->type(adr); adr_type = adr_type->make_ptr(); if (adr_type->isa_oopptr() || - (opcode == Op_StoreP || opcode == Op_StoreN) && + (opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass) && (adr_type == TypeRawPtr::NOTNULL && adr->in(AddPNode::Address)->is_Proj() && adr->in(AddPNode::Address)->in(0)->is_Allocate())) { @@ -572,7 +576,9 @@ case Op_CastPP: case Op_CheckCastPP: case Op_EncodeP: - case Op_DecodeN: { + case Op_DecodeN: + case Op_EncodePKlass: + case Op_DecodeNKlass: { add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL); break; @@ -646,6 +652,7 @@ } case Op_StoreP: case Op_StoreN: + case Op_StoreNKlass: case Op_StorePConditional: case Op_CompareAndSwapP: case Op_CompareAndSwapN: @@ -661,7 +668,7 @@ const Type *adr_type = _igvn->type(adr); adr_type = adr_type->make_ptr(); if (adr_type->isa_oopptr() || - (opcode == Op_StoreP || opcode == Op_StoreN) && + (opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass) && (adr_type == TypeRawPtr::NOTNULL && adr->in(AddPNode::Address)->is_Proj() && adr->in(AddPNode::Address)->in(0)->is_Allocate())) { @@ -2088,7 +2095,7 @@ Node* uncast_base = base->uncast(); int opcode = uncast_base->Opcode(); assert(opcode == Op_ConP || opcode == Op_ThreadLocal || - opcode == Op_CastX2P || uncast_base->is_DecodeN() || + opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base->is_Mem() && uncast_base->bottom_type() == TypeRawPtr::NOTNULL) || (uncast_base->is_Proj() && uncast_base->in(0)->is_Allocate()), "sanity"); } @@ -2837,8 +2844,8 @@ alloc_worklist.append_if_missing(use); } else if (use->is_Phi() || use->is_CheckCastPP() || - use->is_EncodeP() || - use->is_DecodeN() || + use->is_EncodeNarrowPtr() || + use->is_DecodeNarrowPtr() || (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) { alloc_worklist.append_if_missing(use); #ifdef ASSERT --- old/src/share/vm/opto/lcm.cpp 2012-10-08 20:36:34.453266360 +0200 +++ new/src/share/vm/opto/lcm.cpp 2012-10-08 20:36:34.267970474 +0200 @@ -164,6 +164,7 @@ case Op_StoreL: case Op_StoreP: case Op_StoreN: + case Op_StoreNKlass: was_store = true; // Memory op is a store op // Stores will have their address in slot 2 (memory in slot 1). // If the value being nul-checked is in another slot, it means we --- old/src/share/vm/opto/library_call.cpp 2012-10-08 20:36:35.933882371 +0200 +++ new/src/share/vm/opto/library_call.cpp 2012-10-08 20:36:35.714033622 +0200 @@ -4381,7 +4381,7 @@ // 12 - 64-bit VM, compressed klass // 16 - 64-bit VM, normal klass if (base_off % BytesPerLong != 0) { - assert(UseCompressedOops, ""); + assert(UseCompressedKlassPointers, ""); if (is_array) { // Exclude length to copy by 8 bytes words. base_off += sizeof(int); --- old/src/share/vm/opto/live.cpp 2012-10-08 20:36:37.537907771 +0200 +++ new/src/share/vm/opto/live.cpp 2012-10-08 20:36:37.340503691 +0200 @@ -331,6 +331,7 @@ #ifdef _LP64 UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_CastPP || UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_DecodeN || + UseCompressedKlassPointers && check->as_Mach()->ideal_Opcode() == Op_DecodeNKlass || #endif check->as_Mach()->ideal_Opcode() == Op_LoadP || check->as_Mach()->ideal_Opcode() == Op_LoadKlass)) { --- old/src/share/vm/opto/loopTransform.cpp 2012-10-08 20:36:38.951743877 +0200 +++ new/src/share/vm/opto/loopTransform.cpp 2012-10-08 20:36:38.749213544 +0200 @@ -2413,7 +2413,7 @@ break; } int opc = n->Opcode(); - if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreCM) { + if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass || opc == Op_StoreCM) { msg = "oop fills not handled"; break; } --- old/src/share/vm/opto/loopopts.cpp 2012-10-08 20:36:40.461536896 +0200 +++ new/src/share/vm/opto/loopopts.cpp 2012-10-08 20:36:40.257876514 +0200 @@ -550,7 +550,7 @@ // This will likely Split-If, a higher-payoff operation. for (DUIterator_Fast kmax, k = phi->fast_outs(kmax); k < kmax; k++) { Node* use = phi->fast_out(k); - if (use->is_Cmp() || use->is_DecodeN() || use->is_EncodeP()) + if (use->is_Cmp() || use->is_DecodeNarrowPtr() || use->is_EncodeNarrowPtr()) cost += ConditionalMoveLimit; // Is there a use inside the loop? // Note: check only basic types since CMoveP is pinned. @@ -1006,7 +1006,7 @@ // to fold a StoreP and an AddP together (as part of an // address expression) and the AddP and StoreP have // different controls. - if( !x->is_Load() && !x->is_DecodeN() ) _igvn._worklist.yank(x); + if (!x->is_Load() && !x->is_DecodeNarrowPtr()) _igvn._worklist.yank(x); } _igvn.remove_dead_node(n); } --- old/src/share/vm/opto/machnode.cpp 2012-10-08 20:36:41.925124422 +0200 +++ new/src/share/vm/opto/machnode.cpp 2012-10-08 20:36:41.729915483 +0200 @@ -265,7 +265,8 @@ // See if it adds up to a base + offset. if (index != NULL) { const Type* t_index = index->bottom_type(); - if (t_index->isa_narrowoop()) { // EncodeN, LoadN, LoadConN, LoadNKlass. + if (t_index->isa_narrowoop() || t_index->isa_narrowklass()) { // EncodeN, LoadN, LoadConN, LoadNKlass, + // EncodeNKlass, LoadConNklass. // Memory references through narrow oops have a // funny base so grab the type from the index: // [R12 + narrow_oop_reg<<3 + offset] @@ -352,6 +353,10 @@ // 32-bit unscaled narrow oop can be the base of any address expression t = t->make_ptr(); } + if (UseCompressedKlassPointers && Universe::narrow_klass_shift() == 0) { + // 32-bit unscaled narrow oop can be the base of any address expression + t = t->make_ptr(); + } if (t->isa_intptr_t() && offset != 0 && offset != Type::OffsetBot) { // We cannot assert that the offset does not look oop-ish here. // Depending on the heap layout the cardmark base could land --- old/src/share/vm/opto/macro.cpp 2012-10-08 20:36:43.297382353 +0200 +++ new/src/share/vm/opto/macro.cpp 2012-10-08 20:36:43.100962088 +0200 @@ -2125,7 +2125,7 @@ Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); #ifdef _LP64 - if (UseCompressedOops && klass_node->is_DecodeN()) { + if (UseCompressedKlassPointers && klass_node->is_DecodeNKlass()) { assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity"); klass_node->in(1)->init_req(0, ctrl); } else --- old/src/share/vm/opto/matcher.cpp 2012-10-08 20:36:44.774625899 +0200 +++ new/src/share/vm/opto/matcher.cpp 2012-10-08 20:36:44.577793188 +0200 @@ -1058,7 +1058,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 || op == Op_ConN || + if( op == Op_ConI || op == Op_ConP || op == Op_ConN || op == Op_ConNKlass || op == Op_ConF || op == Op_ConD || op == Op_ConL // || op == Op_BoxLock // %%%% enable this and remove (+++) in chaitin.cpp ) { @@ -1450,7 +1450,8 @@ if (j == max_scan) // No post-domination before scan end? return true; // Then break the match tree up } - if (m->is_DecodeN() && Matcher::narrow_oop_use_complex_address()) { + if ((m->is_DecodeN() && Matcher::narrow_oop_use_complex_address()) || + (m->is_DecodeNKlass() && Matcher::narrow_klass_use_complex_address())) { // These are commonly used in address expressions and can // efficiently fold into them on X64 in some cases. return false; @@ -1574,14 +1575,14 @@ // program. The register allocator is free to split uses later to // split live ranges. MachNode* Matcher::find_shared_node(Node* leaf, uint rule) { - if (!leaf->is_Con() && !leaf->is_DecodeN()) return NULL; + if (!leaf->is_Con() && !leaf->is_DecodeNarrowPtr()) return NULL; // See if this Con has already been reduced using this rule. 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()) + if (leaf->is_DecodeNarrowPtr()) return last; // Get the new space root. Node* xroot = new_node(C->root()); @@ -1671,12 +1672,12 @@ // DecodeN node consumed by an address may have different type // then its input. Don't compare types for such case. if (m->adr_type() != mach_at && - (m->in(MemNode::Address)->is_DecodeN() || + (m->in(MemNode::Address)->is_DecodeNarrowPtr() || m->in(MemNode::Address)->is_AddP() && - m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN() || + m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeNarrowPtr() || m->in(MemNode::Address)->is_AddP() && m->in(MemNode::Address)->in(AddPNode::Address)->is_AddP() && - m->in(MemNode::Address)->in(AddPNode::Address)->in(AddPNode::Address)->is_DecodeN())) { + m->in(MemNode::Address)->in(AddPNode::Address)->in(AddPNode::Address)->is_DecodeNarrowPtr())) { mach_at = m->adr_type(); } if (m->adr_type() != mach_at) { @@ -1721,7 +1722,7 @@ guarantee(_proj_list.size() == num_proj, "no allocation during spill generation"); } - if (leaf->is_Con() || leaf->is_DecodeN()) { + if (leaf->is_Con() || leaf->is_DecodeNarrowPtr()) { // Record the con for sharing _shared_nodes.map(leaf->_idx, ex); } @@ -2038,7 +2039,7 @@ continue; // for(int i = ...) } - if( mop == Op_AddP && m->in(AddPNode::Base)->Opcode() == Op_DecodeN ) { + if( mop == Op_AddP && m->in(AddPNode::Base)->is_DecodeNarrowPtr()) { // Bases used in addresses must be shared but since // they are shared through a DecodeN they may appear // to have a single use so force sharing here. @@ -2277,7 +2278,7 @@ if (has_new_node(val)) { Node* new_val = new_node(val); if (is_decoden) { - assert(val->is_DecodeN() && val->in(0) == NULL, "sanity"); + assert(val->is_DecodeNarrowPtr() && val->in(0) == NULL, "sanity"); // Note: new_val may have a control edge if // the original ideal node DecodeN was matched before // it was unpinned in Matcher::collect_null_checks(). --- old/src/share/vm/opto/matcher.hpp 2012-10-08 20:36:46.228231902 +0200 +++ new/src/share/vm/opto/matcher.hpp 2012-10-08 20:36:46.039502330 +0200 @@ -380,6 +380,7 @@ static const bool clone_shift_expressions; static bool narrow_oop_use_complex_address(); + static bool narrow_klass_use_complex_address(); // Generate implicit null check for narrow oops if it can fold // into address expression (x64). --- old/src/share/vm/opto/memnode.cpp 2012-10-08 20:36:47.641920405 +0200 +++ new/src/share/vm/opto/memnode.cpp 2012-10-08 20:36:47.437223306 +0200 @@ -714,10 +714,12 @@ continue; case Op_DecodeN: // No change to NULL-ness, so peek thru + case Op_DecodeNKlass: adr = adr->in(1); continue; case Op_EncodeP: + case Op_EncodePKlass: // EncodeP node's control edge could be set by this method // when EncodeP node depends on CastPP node. // @@ -794,6 +796,7 @@ case Op_LoadNKlass: // Loading from within a klass case Op_ConP: // Loading from a klass case Op_ConN: // Loading from a klass + case Op_ConNKlass: // 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 @@ -900,7 +903,7 @@ } else #endif { - assert(!adr->bottom_type()->is_ptr_to_narrowoop(), "should have got back a narrow oop"); + assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop"); return new (C) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr()); } } @@ -1894,13 +1897,13 @@ const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); assert(adr_type != NULL, "expecting TypeKlassPtr"); #ifdef _LP64 - if (adr_type->is_ptr_to_narrowoop()) { + if (adr_type->is_ptr_to_narrowklass()) { assert(UseCompressedKlassPointers, "no compressed klasses"); - Node* load_klass = gvn.transform(new (C) LoadNKlassNode(ctl, mem, adr, at, tk->make_narrowoop())); - return new (C) DecodeNNode(load_klass, load_klass->bottom_type()->make_ptr()); + Node* load_klass = gvn.transform(new (C) LoadNKlassNode(ctl, mem, adr, at, tk->make_narrowklass())); + return new (C) DecodeNKlassNode(load_klass, load_klass->bottom_type()->make_ptr()); } #endif - assert(!adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop"); + assert(!adr_type->is_ptr_to_narrowklass() && !adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop"); return new (C) LoadKlassNode(ctl, mem, adr, at, tk); } @@ -2110,7 +2113,7 @@ if (t == Type::TOP) return t; - return t->make_narrowoop(); + return t->make_narrowklass(); } //------------------------------Identity--------------------------------------- @@ -2121,9 +2124,10 @@ const Type *t = phase->type( x ); if( t == Type::TOP ) return x; - if( t->isa_narrowoop()) return x; + if( t->isa_narrowklass()) return x; + assert (!t->isa_narrowoop(), "no narrow oop here"); - return phase->transform(new (phase->C) EncodePNode(x, t->make_narrowoop())); + return phase->transform(new (phase->C) EncodePKlassNode(x, t->make_narrowklass())); } //------------------------------Value----------------------------------------- @@ -2228,12 +2232,15 @@ case T_ADDRESS: case T_OBJECT: #ifdef _LP64 - if (adr->bottom_type()->is_ptr_to_narrowoop() || - (UseCompressedKlassPointers && val->bottom_type()->isa_klassptr() && - adr->bottom_type()->isa_rawptr())) { + if (adr->bottom_type()->is_ptr_to_narrowoop()) { val = gvn.transform(new (C) EncodePNode(val, val->bottom_type()->make_narrowoop())); return new (C) StoreNNode(ctl, mem, adr, adr_type, val); - } else + } else if (adr->bottom_type()->is_ptr_to_narrowklass() || + (UseCompressedKlassPointers && val->bottom_type()->isa_klassptr() && + adr->bottom_type()->isa_rawptr())) { + val = gvn.transform(new (C) EncodePKlassNode(val, val->bottom_type()->make_narrowklass())); + return new (C) StoreNKlassNode(ctl, mem, adr, adr_type, val); + } #endif { return new (C) StorePNode(ctl, mem, adr, adr_type, val); --- old/src/share/vm/opto/memnode.hpp 2012-10-08 20:36:49.280551022 +0200 +++ new/src/share/vm/opto/memnode.hpp 2012-10-08 20:36:49.085691469 +0200 @@ -437,12 +437,12 @@ // 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 ) + LoadNKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeNarrowKlass *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 int store_Opcode() const { return Op_StoreNKlass; } + virtual BasicType memory_type() const { return T_NARROWKLASS; } virtual const Type *Value( PhaseTransform *phase ) const; virtual Node *Identity( PhaseTransform *phase ); @@ -593,6 +593,15 @@ virtual BasicType memory_type() const { return T_NARROWOOP; } }; +//------------------------------StoreNKlassNode-------------------------------------- +// Store narrow klass to memory +class StoreNKlassNode : public StoreNNode { +public: + StoreNKlassNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val ) : StoreNNode(c,mem,adr,at,val) {} + virtual int Opcode() const; + virtual BasicType memory_type() const { return T_NARROWKLASS; } +}; + //------------------------------StoreCMNode----------------------------------- // Store card-mark byte to memory for CM // The last StoreCM before a SafePoint must be preserved and occur after its "oop" store --- old/src/share/vm/opto/node.hpp 2012-10-08 20:36:50.745172003 +0200 +++ new/src/share/vm/opto/node.hpp 2012-10-08 20:36:50.545454808 +0200 @@ -62,8 +62,12 @@ class ConNode; class CountedLoopNode; class CountedLoopEndNode; +class DecodeNarrowPtrNode; class DecodeNNode; +class DecodeNKlassNode; +class EncodeNarrowPtrNode; class EncodePNode; +class EncodePKlassNode; class FastLockNode; class FastUnlockNode; class IfNode; @@ -585,8 +589,12 @@ 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(DecodeNarrowPtr, Type, 5) + DEFINE_CLASS_ID(DecodeN, DecodeNarrowPtr, 0) + DEFINE_CLASS_ID(DecodeNKlass, DecodeNarrowPtr, 1) + DEFINE_CLASS_ID(EncodeNarrowPtr, Type, 6) + DEFINE_CLASS_ID(EncodeP, EncodeNarrowPtr, 0) + DEFINE_CLASS_ID(EncodePKlass, EncodeNarrowPtr, 1) DEFINE_CLASS_ID(Proj, Node, 3) DEFINE_CLASS_ID(CatchProj, Proj, 0) @@ -706,8 +714,12 @@ DEFINE_CLASS_QUERY(Cmp) DEFINE_CLASS_QUERY(CountedLoop) DEFINE_CLASS_QUERY(CountedLoopEnd) + DEFINE_CLASS_QUERY(DecodeNarrowPtr) DEFINE_CLASS_QUERY(DecodeN) + DEFINE_CLASS_QUERY(DecodeNKlass) + DEFINE_CLASS_QUERY(EncodeNarrowPtr) DEFINE_CLASS_QUERY(EncodeP) + DEFINE_CLASS_QUERY(EncodePKlass) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) DEFINE_CLASS_QUERY(If) --- old/src/share/vm/opto/parse2.cpp 2012-10-08 20:36:52.188765318 +0200 +++ new/src/share/vm/opto/parse2.cpp 2012-10-08 20:36:51.997600444 +0200 @@ -1239,7 +1239,7 @@ static Node* extract_obj_from_klass_load(PhaseGVN* gvn, Node* n) { Node* ldk; - if (n->is_DecodeN()) { + if (n->is_DecodeNKlass()) { if (n->in(1)->Opcode() != Op_LoadNKlass) { return NULL; } else { --- old/src/share/vm/opto/subnode.cpp 2012-10-08 20:36:53.651823290 +0200 +++ new/src/share/vm/opto/subnode.cpp 2012-10-08 20:36:53.466769805 +0200 @@ -789,7 +789,7 @@ // Now check for LoadKlass on left. Node* ldk1 = in(1); - if (ldk1->is_DecodeN()) { + if (ldk1->is_DecodeNKlass()) { ldk1 = ldk1->in(1); if (ldk1->Opcode() != Op_LoadNKlass ) return NULL; @@ -814,7 +814,7 @@ // Check for a LoadKlass from primary supertype array. // Any nested loadklass from loadklass+con must be from the p.s. array. - if (ldk2->is_DecodeN()) { + if (ldk2->is_DecodeNKlass()) { // Keep ldk2 as DecodeN since it could be used in CmpP below. if (ldk2->in(1)->Opcode() != Op_LoadNKlass ) return NULL; --- old/src/share/vm/opto/type.cpp 2012-10-08 20:36:54.929163812 +0200 +++ new/src/share/vm/opto/type.cpp 2012-10-08 20:36:54.723785021 +0200 @@ -57,6 +57,7 @@ { Bad, T_LONG, "long:", false, Op_RegL, relocInfo::none }, // Long { Half, T_VOID, "half", false, 0, relocInfo::none }, // Half { Bad, T_NARROWOOP, "narrowoop:", false, Op_RegN, relocInfo::none }, // NarrowOop + { Bad, T_NARROWKLASS,"narrowklass:", false, Op_RegN, relocInfo::none }, // NarrowKlass { Bad, T_ILLEGAL, "tuple:", false, Node::NotAMachineReg, relocInfo::none }, // Tuple { Bad, T_ARRAY, "array:", false, Node::NotAMachineReg, relocInfo::none }, // Array @@ -332,6 +333,8 @@ TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR ); TypeNarrowOop::BOTTOM = TypeNarrowOop::make( TypeInstPtr::BOTTOM ); + TypeNarrowKlass::NULL_PTR = TypeNarrowKlass::make( TypePtr::NULL_PTR ); + mreg2type[Op_Node] = Type::BOTTOM; mreg2type[Op_Set ] = 0; mreg2type[Op_RegN] = TypeNarrowOop::BOTTOM; @@ -395,34 +398,36 @@ longpair[1] = TypeLong::LONG; TypeTuple::LONG_PAIR = TypeTuple::make(2, longpair); - _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; - _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; - _const_basic_type[T_CHAR] = TypeInt::CHAR; - _const_basic_type[T_BYTE] = TypeInt::BYTE; - _const_basic_type[T_SHORT] = TypeInt::SHORT; - _const_basic_type[T_INT] = TypeInt::INT; - _const_basic_type[T_LONG] = TypeLong::LONG; - _const_basic_type[T_FLOAT] = Type::FLOAT; - _const_basic_type[T_DOUBLE] = Type::DOUBLE; - _const_basic_type[T_OBJECT] = TypeInstPtr::BOTTOM; - _const_basic_type[T_ARRAY] = TypeInstPtr::BOTTOM; // there is no separate bottom for arrays - _const_basic_type[T_VOID] = TypePtr::NULL_PTR; // reflection represents void this way - _const_basic_type[T_ADDRESS] = TypeRawPtr::BOTTOM; // both interpreter return addresses & random raw ptrs - _const_basic_type[T_CONFLICT]= Type::BOTTOM; // why not? - - _zero_type[T_NARROWOOP] = TypeNarrowOop::NULL_PTR; - _zero_type[T_BOOLEAN] = TypeInt::ZERO; // false == 0 - _zero_type[T_CHAR] = TypeInt::ZERO; // '\0' == 0 - _zero_type[T_BYTE] = TypeInt::ZERO; // 0x00 == 0 - _zero_type[T_SHORT] = TypeInt::ZERO; // 0x0000 == 0 - _zero_type[T_INT] = TypeInt::ZERO; - _zero_type[T_LONG] = TypeLong::ZERO; - _zero_type[T_FLOAT] = TypeF::ZERO; - _zero_type[T_DOUBLE] = TypeD::ZERO; - _zero_type[T_OBJECT] = TypePtr::NULL_PTR; - _zero_type[T_ARRAY] = TypePtr::NULL_PTR; // null array is null oop - _zero_type[T_ADDRESS] = TypePtr::NULL_PTR; // raw pointers use the same null - _zero_type[T_VOID] = Type::TOP; // the only void value is no value at all + _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; + _const_basic_type[T_NARROWKLASS] = Type::BOTTOM; + _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; + _const_basic_type[T_CHAR] = TypeInt::CHAR; + _const_basic_type[T_BYTE] = TypeInt::BYTE; + _const_basic_type[T_SHORT] = TypeInt::SHORT; + _const_basic_type[T_INT] = TypeInt::INT; + _const_basic_type[T_LONG] = TypeLong::LONG; + _const_basic_type[T_FLOAT] = Type::FLOAT; + _const_basic_type[T_DOUBLE] = Type::DOUBLE; + _const_basic_type[T_OBJECT] = TypeInstPtr::BOTTOM; + _const_basic_type[T_ARRAY] = TypeInstPtr::BOTTOM; // there is no separate bottom for arrays + _const_basic_type[T_VOID] = TypePtr::NULL_PTR; // reflection represents void this way + _const_basic_type[T_ADDRESS] = TypeRawPtr::BOTTOM; // both interpreter return addresses & random raw ptrs + _const_basic_type[T_CONFLICT] = Type::BOTTOM; // why not? + + _zero_type[T_NARROWOOP] = TypeNarrowOop::NULL_PTR; + _zero_type[T_NARROWKLASS] = TypeNarrowKlass::NULL_PTR; + _zero_type[T_BOOLEAN] = TypeInt::ZERO; // false == 0 + _zero_type[T_CHAR] = TypeInt::ZERO; // '\0' == 0 + _zero_type[T_BYTE] = TypeInt::ZERO; // 0x00 == 0 + _zero_type[T_SHORT] = TypeInt::ZERO; // 0x0000 == 0 + _zero_type[T_INT] = TypeInt::ZERO; + _zero_type[T_LONG] = TypeLong::ZERO; + _zero_type[T_FLOAT] = TypeF::ZERO; + _zero_type[T_DOUBLE] = TypeD::ZERO; + _zero_type[T_OBJECT] = TypePtr::NULL_PTR; + _zero_type[T_ARRAY] = TypePtr::NULL_PTR; // null array is null oop + _zero_type[T_ADDRESS] = TypePtr::NULL_PTR; // raw pointers use the same null + _zero_type[T_VOID] = Type::TOP; // the only void value is no value at all // get_zero_type() should not happen for T_CONFLICT _zero_type[T_CONFLICT]= NULL; @@ -563,9 +568,14 @@ const Type* result = make_ptr()->meet(t->make_ptr()); return result->make_narrowoop(); } + if (isa_narrowklass() && t->isa_narrowklass()) { + const Type* result = make_ptr()->meet(t->make_ptr()); + return result->make_narrowklass(); + } const Type *mt = xmeet(t); if (isa_narrowoop() || t->isa_narrowoop()) return mt; + if (isa_narrowklass() || t->isa_narrowklass()) return mt; #ifdef ASSERT assert( mt == t->xmeet(this), "meet not commutative" ); const Type* dual_join = mt->_dual; @@ -635,6 +645,9 @@ case NarrowOop: return t->xmeet(this); + case NarrowKlass: + return t->xmeet(this); + case Bad: // Type check default: // Bogus type not in lattice typerr(t); @@ -693,6 +706,7 @@ Bad, // Long - handled in v-call Half, // Half Bad, // NarrowOop - handled in v-call + Bad, // NarrowKlass - handled in v-call Bad, // Tuple - handled in v-call Bad, // Array - handled in v-call @@ -756,6 +770,8 @@ dump2(d,1, st); if (is_ptr_to_narrowoop()) { st->print(" [narrow]"); + } else if (is_ptr_to_narrowklass()) { + st->print(" [narrowklass]"); } } #endif @@ -838,6 +854,7 @@ case MetadataPtr: case KlassPtr: case NarrowOop: + case NarrowKlass: case Int: case Long: case DoubleTop: @@ -955,6 +972,7 @@ case MetadataPtr: case KlassPtr: case NarrowOop: + case NarrowKlass: case Int: case Long: case FloatTop: @@ -1109,6 +1127,7 @@ case MetadataPtr: case KlassPtr: case NarrowOop: + case NarrowKlass: case Long: case FloatTop: case FloatCon: @@ -1366,6 +1385,7 @@ case MetadataPtr: case KlassPtr: case NarrowOop: + case NarrowKlass: case Int: case FloatTop: case FloatCon: @@ -2096,6 +2116,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: @@ -2350,17 +2371,18 @@ _const_oop(o), _klass(k), _klass_is_exact(xk), _is_ptr_to_narrowoop(false), + _is_ptr_to_narrowklass(false), _instance_id(instance_id) { #ifdef _LP64 - if (UseCompressedOops && _offset != 0) { + if (_offset != 0) { if (_offset == oopDesc::klass_offset_in_bytes()) { - _is_ptr_to_narrowoop = UseCompressedKlassPointers; + _is_ptr_to_narrowklass = UseCompressedKlassPointers; } else if (klass() == NULL) { // Array with unknown body type assert(this->isa_aryptr(), "only arrays without klass"); - _is_ptr_to_narrowoop = true; + _is_ptr_to_narrowoop = UseCompressedOops; } else if (this->isa_aryptr()) { - _is_ptr_to_narrowoop = (klass()->is_obj_array_klass() && + _is_ptr_to_narrowoop = (UseCompressedOops && klass()->is_obj_array_klass() && _offset != arrayOopDesc::length_offset_in_bytes()); } else if (klass()->is_instance_klass()) { ciInstanceKlass* ik = klass()->as_instance_klass(); @@ -2369,7 +2391,7 @@ // Perm objects don't use compressed references } else if (_offset == OffsetBot || _offset == OffsetTop) { // unsafe access - _is_ptr_to_narrowoop = true; + _is_ptr_to_narrowoop = UseCompressedOops; } else { // exclude unsafe ops assert(this->isa_instptr(), "must be an instance ptr."); @@ -2387,22 +2409,22 @@ ciField* field = k->get_field_by_offset(_offset, true); assert(field != NULL, "missing field"); BasicType basic_elem_type = field->layout_type(); - _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || - basic_elem_type == T_ARRAY); + _is_ptr_to_narrowoop = UseCompressedOops && (basic_elem_type == T_OBJECT || + basic_elem_type == T_ARRAY); } else { // Instance fields 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); + _is_ptr_to_narrowoop = UseCompressedOops && (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; + _is_ptr_to_narrowoop = UseCompressedOops; } else { // Type for the copy start in LibraryCallKit::inline_native_clone(). - _is_ptr_to_narrowoop = true; + _is_ptr_to_narrowoop = UseCompressedOops; } } } @@ -2475,6 +2497,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: @@ -2925,6 +2948,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: @@ -3353,6 +3377,7 @@ case T_NARROWOOP: etype = T_OBJECT; break; + case T_NARROWKLASS: case T_CONFLICT: case T_ILLEGAL: case T_VOID: @@ -3425,6 +3450,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: @@ -3671,23 +3697,27 @@ //============================================================================= -const TypeNarrowOop *TypeNarrowOop::BOTTOM; -const TypeNarrowOop *TypeNarrowOop::NULL_PTR; - - -const TypeNarrowOop* TypeNarrowOop::make(const TypePtr* type) { - return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons(); -} //------------------------------hash------------------------------------------- // Type-specific hashing function. -int TypeNarrowOop::hash(void) const { +int TypeNarrowPtr::hash(void) const { return _ptrtype->hash() + 7; } +bool TypeNarrowPtr::singleton(void) const { // TRUE if type is a singleton + return _ptrtype->singleton(); +} + +bool TypeNarrowPtr::empty(void) const { + return _ptrtype->empty(); +} + +intptr_t TypeNarrowPtr::get_con() const { + return _ptrtype->get_con(); +} -bool TypeNarrowOop::eq( const Type *t ) const { - const TypeNarrowOop* tc = t->isa_narrowoop(); +bool TypeNarrowPtr::eq( const Type *t ) const { + const TypeNarrowPtr* tc = isa_same_narrowptr(t); if (tc != NULL) { if (_ptrtype->base() != tc->_ptrtype->base()) { return false; @@ -3697,22 +3727,46 @@ return false; } -bool TypeNarrowOop::singleton(void) const { // TRUE if type is a singleton - return _ptrtype->singleton(); +const Type *TypeNarrowPtr::xdual() const { // Compute dual right now. + const TypePtr* odual = _ptrtype->dual()->is_ptr(); + return make_same_narrowptr(odual); } -bool TypeNarrowOop::empty(void) const { - return _ptrtype->empty(); + +const Type *TypeNarrowPtr::filter( const Type *kills ) const { + if (isa_same_narrowptr(kills)) { + const Type* ft =_ptrtype->filter(is_same_narrowptr(kills)->_ptrtype); + if (ft->empty()) + return Type::TOP; // Canonical empty value + if (ft->isa_ptr()) { + return make_hash_same_narrowptr(ft->isa_ptr()); + } + return ft; + } else if (kills->isa_ptr()) { + const Type* ft = _ptrtype->join(kills); + if (ft->empty()) + return Type::TOP; // Canonical empty value + return ft; + } else { + return Type::TOP; + } } //------------------------------xmeet------------------------------------------ // Compute the MEET of two types. It returns a new Type object. -const Type *TypeNarrowOop::xmeet( const Type *t ) const { +const Type *TypeNarrowPtr::xmeet( const Type *t ) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? + if (t->base() == base()) { + const Type* result = _ptrtype->xmeet(t->make_ptr()); + if (result->isa_ptr()) { + return make_hash_same_narrowptr(result->is_ptr()); + } + return result; + } - // Current "this->_base" is OopPtr + // Current "this->_base" is NarrowKlass or NarrowOop switch (t->base()) { // switch on original type case Int: // Mixing ints & oops happens when javac @@ -3730,20 +3784,14 @@ case AryPtr: case MetadataPtr: case KlassPtr: + case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: return this; - case NarrowOop: { - const Type* result = _ptrtype->xmeet(t->make_ptr()); - if (result->isa_ptr()) { - return TypeNarrowOop::make(result->is_ptr()); - } - return result; - } - default: // All else is a mistake typerr(t); @@ -3752,42 +3800,40 @@ return this; } -const Type *TypeNarrowOop::xdual() const { // Compute dual right now. - const TypePtr* odual = _ptrtype->dual()->is_ptr(); - return new TypeNarrowOop(odual); +#ifndef PRODUCT +void TypeNarrowPtr::dump2( Dict & d, uint depth, outputStream *st ) const { + _ptrtype->dump2(d, depth, st); } +#endif -const Type *TypeNarrowOop::filter( const Type *kills ) const { - if (kills->isa_narrowoop()) { - const Type* ft =_ptrtype->filter(kills->is_narrowoop()->_ptrtype); - if (ft->empty()) - return Type::TOP; // Canonical empty value - if (ft->isa_ptr()) { - return make(ft->isa_ptr()); - } - return ft; - } else if (kills->isa_ptr()) { - const Type* ft = _ptrtype->join(kills); - if (ft->empty()) - return Type::TOP; // Canonical empty value - return ft; - } else { - return Type::TOP; - } -} +const TypeNarrowOop *TypeNarrowOop::BOTTOM; +const TypeNarrowOop *TypeNarrowOop::NULL_PTR; -intptr_t TypeNarrowOop::get_con() const { - return _ptrtype->get_con(); +const TypeNarrowOop* TypeNarrowOop::make(const TypePtr* type) { + return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons(); } + #ifndef PRODUCT void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const { st->print("narrowoop: "); - _ptrtype->dump2(d, depth, st); + TypeNarrowPtr::dump2(d, depth, st); } #endif +const TypeNarrowKlass *TypeNarrowKlass::NULL_PTR; + +const TypeNarrowKlass* TypeNarrowKlass::make(const TypePtr* type) { + return (const TypeNarrowKlass*)(new TypeNarrowKlass(type))->hashcons(); +} + +#ifndef PRODUCT +void TypeNarrowKlass::dump2( Dict & d, uint depth, outputStream *st ) const { + st->print("narrowklass: "); + TypeNarrowPtr::dump2(d, depth, st); +} +#endif //------------------------------eq--------------------------------------------- @@ -3878,6 +3924,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: @@ -4169,6 +4216,7 @@ case DoubleCon: case DoubleBot: case NarrowOop: + case NarrowKlass: case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: --- old/src/share/vm/opto/type.hpp 2012-10-08 20:36:56.328030604 +0200 +++ new/src/share/vm/opto/type.hpp 2012-10-08 20:36:56.131746305 +0200 @@ -48,7 +48,9 @@ class TypeF; class TypeInt; class TypeLong; -class TypeNarrowOop; +class TypeNarrowPtr; +class TypeNarrowOop; +class TypeNarrowKlass; class TypeAry; class TypeTuple; class TypeVect; @@ -81,6 +83,7 @@ Long, // Long integer range (lo-hi) Half, // Placeholder half of doubleword NarrowOop, // Compressed oop pointer + NarrowKlass, // Compressed klass pointer Tuple, // Method signature or object layout Array, // Array types @@ -229,6 +232,7 @@ // Returns true if this pointer points at memory which contains a // compressed oop references. bool is_ptr_to_narrowoop() const; + bool is_ptr_to_narrowklass() const; // Convenience access float getf() const; @@ -252,6 +256,8 @@ 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 TypeNarrowKlass *is_narrowklass() const; // compressed klass pointer + const TypeNarrowKlass *isa_narrowklass() 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 TypeInstPtr *isa_instptr() const; // Returns NULL if not InstPtr @@ -278,6 +284,10 @@ // of this pointer type. const TypeNarrowOop* make_narrowoop() const; + // Returns this compressed klass pointer or the equivalent + // compressed version of this pointer type. + const TypeNarrowKlass* make_narrowklass() const; + // Special test for register pressure heuristic bool is_floatingpoint() const; // True if Float or Double base type @@ -670,7 +680,7 @@ // Otherwise the _base will indicate which subset of pointers is affected, // and the class will be inherited from. class TypePtr : public Type { - friend class TypeNarrowOop; + friend class TypeNarrowPtr; public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; protected: @@ -781,6 +791,7 @@ // Does the type exclude subclasses of the klass? (Inexact == polymorphic.) bool _klass_is_exact; bool _is_ptr_to_narrowoop; + bool _is_ptr_to_narrowklass; // If not InstanceTop or InstanceBot, indicates that this is // a particular instance of this type which is distinct. @@ -825,6 +836,7 @@ // 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_ptr_to_narrowklass_nv() const { return _is_ptr_to_narrowklass; } bool is_known_instance() const { return _instance_id > 0; } int instance_id() const { return _instance_id; } @@ -1122,22 +1134,21 @@ #endif }; -//------------------------------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 -// oopness of the compressed oop value when we expose the conversion -// between the normal and the compressed form. -class TypeNarrowOop : public Type { +class TypeNarrowPtr : public Type { protected: const TypePtr* _ptrtype; // Could be TypePtr::NULL_PTR - TypeNarrowOop( const TypePtr* ptrtype): Type(NarrowOop), - _ptrtype(ptrtype) { + TypeNarrowPtr(TYPES t, const TypePtr* ptrtype): _ptrtype(ptrtype), + Type(t) { assert(ptrtype->offset() == 0 || ptrtype->offset() == OffsetBot || ptrtype->offset() == OffsetTop, "no real offsets"); } + + virtual const TypeNarrowPtr *isa_same_narrowptr(const Type *t) const = 0; + virtual const TypeNarrowPtr *is_same_narrowptr(const Type *t) const = 0; + virtual const TypeNarrowPtr *make_same_narrowptr(const TypePtr *t) const = 0; + virtual const TypeNarrowPtr *make_hash_same_narrowptr(const TypePtr *t) const = 0; public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1150,20 +1161,54 @@ // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter( const Type *kills ) const; - + virtual bool empty(void) const; // TRUE if type is vacuous + // returns the equivalent ptr type for this compressed pointer + const TypePtr *get_ptrtype() const { + return _ptrtype; + } + +#ifndef PRODUCT + virtual void dump2( Dict &d, uint depth, outputStream *st ) const; +#endif +}; + +//------------------------------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 +// oopness of the compressed oop value when we expose the conversion +// between the normal and the compressed form. +class TypeNarrowOop : public TypeNarrowPtr { +protected: + TypeNarrowOop( const TypePtr* ptrtype): TypeNarrowPtr(NarrowOop, ptrtype) { + } + + virtual const TypeNarrowPtr *isa_same_narrowptr(const Type *t) const { + return t->isa_narrowoop(); + } + + virtual const TypeNarrowPtr *is_same_narrowptr(const Type *t) const { + return t->is_narrowoop(); + } + + virtual const TypeNarrowPtr *make_same_narrowptr(const TypePtr *t) const { + return new TypeNarrowOop(t); + } + + virtual const TypeNarrowPtr *make_hash_same_narrowptr(const TypePtr *t) const { + return (const TypeNarrowPtr*)((new TypeNarrowOop(t))->hashcons()); + } + +public: + static const TypeNarrowOop *make( const TypePtr* type); static const TypeNarrowOop* make_from_constant(ciObject* con, bool require_constant = false) { return make(TypeOopPtr::make_from_constant(con, require_constant)); } - // returns the equivalent ptr type for this compressed pointer - const TypePtr *get_ptrtype() const { - return _ptrtype; - } - static const TypeNarrowOop *BOTTOM; static const TypeNarrowOop *NULL_PTR; @@ -1172,6 +1217,42 @@ #endif }; +//------------------------------TypeNarrowKlass---------------------------------- +// A compressed reference to klass pointer. This type wraps around a +// preexisting TypeKlassPtr and forwards most of it's operations to +// the underlying type. +class TypeNarrowKlass : public TypeNarrowPtr { +protected: + TypeNarrowKlass( const TypePtr* ptrtype): TypeNarrowPtr(NarrowKlass, ptrtype) { + } + + virtual const TypeNarrowPtr *isa_same_narrowptr(const Type *t) const { + return t->isa_narrowklass(); + } + + virtual const TypeNarrowPtr *is_same_narrowptr(const Type *t) const { + return t->is_narrowklass(); + } + + virtual const TypeNarrowPtr *make_same_narrowptr(const TypePtr *t) const { + return new TypeNarrowKlass(t); + } + + virtual const TypeNarrowPtr *make_hash_same_narrowptr(const TypePtr *t) const { + return (const TypeNarrowPtr*)((new TypeNarrowKlass(t))->hashcons()); + } + +public: + static const TypeNarrowKlass *make( const TypePtr* type); + + // static const TypeNarrowKlass *BOTTOM; + static const TypeNarrowKlass *NULL_PTR; + +#ifndef PRODUCT + virtual void dump2( Dict &d, uint depth, outputStream *st ) const; +#endif +}; + //------------------------------TypeFunc--------------------------------------- // Class of Array Types class TypeFunc : public Type { @@ -1221,6 +1302,14 @@ #endif } +inline bool Type::is_ptr_to_narrowklass() const { +#ifdef _LP64 + return (isa_oopptr() != NULL && is_oopptr()->is_ptr_to_narrowklass_nv()); +#else + return false; +#endif +} + inline float Type::getf() const { assert( _base == FloatCon, "Not a FloatCon" ); return ((TypeF*)this)->_f; @@ -1346,6 +1435,15 @@ return (_base == NarrowOop) ? (TypeNarrowOop*)this : NULL; } +inline const TypeNarrowKlass *Type::is_narrowklass() const { + assert(_base == NarrowKlass, "Not a narrow oop" ) ; + return (TypeNarrowKlass*)this; +} + +inline const TypeNarrowKlass *Type::isa_narrowklass() const { + return (_base == NarrowKlass) ? (TypeNarrowKlass*)this : NULL; +} + inline const TypeMetadataPtr *Type::is_metadataptr() const { // MetadataPtr is the first and CPCachePtr the last assert(_base == MetadataPtr, "Not a metadata pointer" ) ; @@ -1367,7 +1465,8 @@ inline const TypePtr* Type::make_ptr() const { return (_base == NarrowOop) ? is_narrowoop()->get_ptrtype() : - (isa_ptr() ? is_ptr() : NULL); + ((_base == NarrowKlass) ? is_narrowklass()->get_ptrtype() : + (isa_ptr() ? is_ptr() : NULL)); } inline const TypeOopPtr* Type::make_oopptr() const { @@ -1379,6 +1478,11 @@ (isa_ptr() ? TypeNarrowOop::make(is_ptr()) : NULL); } +inline const TypeNarrowKlass* Type::make_narrowklass() const { + return (_base == NarrowKlass) ? is_narrowklass() : + (isa_ptr() ? TypeNarrowKlass::make(is_ptr()) : NULL); +} + inline bool Type::is_floatingpoint() const { if( (_base == FloatCon) || (_base == FloatBot) || (_base == DoubleCon) || (_base == DoubleBot) ) --- old/src/share/vm/runtime/arguments.cpp 2012-10-08 20:36:57.762006082 +0200 +++ new/src/share/vm/runtime/arguments.cpp 2012-10-08 20:36:57.560934392 +0200 @@ -1423,10 +1423,9 @@ FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); } else { // Turn on UseCompressedKlassPointers too - // The compiler is broken for this so turn it on when the compiler is fixed. - // if (FLAG_IS_DEFAULT(UseCompressedKlassPointers)) { - // FLAG_SET_ERGO(bool, UseCompressedKlassPointers, true); - // } + if (FLAG_IS_DEFAULT(UseCompressedKlassPointers)) { + FLAG_SET_ERGO(bool, UseCompressedKlassPointers, true); + } // Set the ClassMetaspaceSize to something that will not need to be // expanded, since it cannot be expanded. if (UseCompressedKlassPointers && FLAG_IS_DEFAULT(ClassMetaspaceSize)) { --- old/src/share/vm/runtime/stubRoutines.cpp 2012-10-08 20:36:59.263885989 +0200 +++ new/src/share/vm/runtime/stubRoutines.cpp 2012-10-08 20:36:59.081688396 +0200 @@ -421,6 +421,7 @@ case T_ARRAY: case T_OBJECT: case T_NARROWOOP: + case T_NARROWKLASS: case T_ADDRESS: // Currently unsupported return NULL; --- old/src/share/vm/runtime/vmStructs.cpp 2012-10-08 20:37:00.635825649 +0200 +++ new/src/share/vm/runtime/vmStructs.cpp 2012-10-08 20:37:00.409696362 +0200 @@ -454,6 +454,8 @@ static_field(Universe, _narrow_oop._base, address) \ static_field(Universe, _narrow_oop._shift, int) \ static_field(Universe, _narrow_oop._use_implicit_null_checks, bool) \ + static_field(Universe, _narrow_klass._base, address) \ + static_field(Universe, _narrow_klass._shift, int) \ \ /**********************************************************************************/ \ /* Generation and Space hierarchies */ \ @@ -1727,6 +1729,8 @@ declare_c2_type(CMoveNNode, CMoveNode) \ declare_c2_type(EncodePNode, TypeNode) \ declare_c2_type(DecodeNNode, TypeNode) \ + declare_c2_type(EncodePKlassNode, TypeNode) \ + declare_c2_type(DecodeNKlassNode, TypeNode) \ declare_c2_type(ConstraintCastNode, TypeNode) \ declare_c2_type(CastIINode, ConstraintCastNode) \ declare_c2_type(CastPPNode, ConstraintCastNode) \ @@ -1823,6 +1827,7 @@ declare_c2_type(StoreDNode, StoreNode) \ declare_c2_type(StorePNode, StoreNode) \ declare_c2_type(StoreNNode, StoreNode) \ + declare_c2_type(StoreNKlassNode, StoreNode) \ declare_c2_type(StoreCMNode, StoreNode) \ declare_c2_type(LoadPLockedNode, LoadPNode) \ declare_c2_type(SCMemProjNode, ProjNode) \ --- old/src/share/vm/utilities/globalDefinitions.cpp 2012-10-08 20:37:02.196546922 +0200 +++ new/src/share/vm/utilities/globalDefinitions.cpp 2012-10-08 20:37:01.919306365 +0200 @@ -111,11 +111,12 @@ case T_DOUBLE: case T_LONG: case T_OBJECT: - case T_ADDRESS: // random raw pointer - case T_METADATA: // metadata pointer - case T_NARROWOOP: // compressed pointer - case T_CONFLICT: // might as well support a bottom type - case T_VOID: // padding or other unaddressed word + case T_ADDRESS: // random raw pointer + case T_METADATA: // metadata pointer + case T_NARROWOOP: // compressed pointer + case T_NARROWKLASS: // compressed klass pointer + case T_CONFLICT: // might as well support a bottom type + case T_VOID: // padding or other unaddressed word // layout type must map to itself assert(vt == ft, ""); break; @@ -179,7 +180,7 @@ // Map BasicType to signature character -char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'V', 0, 0, 0, 0}; +char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'V', 0, 0, 0, 0, 0}; // Map BasicType to Java type name const char* type2name_tab[T_CONFLICT+1] = { @@ -198,6 +199,7 @@ "*address*", "*narrowoop*", "*metadata*", + "*narrowklass*", "*conflict*" }; @@ -213,7 +215,7 @@ // Map BasicType to size in words -int type2size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, -1}; +int type2size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 1, -1}; BasicType type2field[T_CONFLICT+1] = { (BasicType)0, // 0, @@ -234,7 +236,8 @@ T_ADDRESS, // T_ADDRESS = 15, T_NARROWOOP, // T_NARROWOOP= 16, T_METADATA, // T_METADATA = 17, - T_CONFLICT // T_CONFLICT = 18, + T_NARROWKLASS, // T_NARROWKLASS = 18, + T_CONFLICT // T_CONFLICT = 19, }; @@ -257,30 +260,32 @@ T_ADDRESS, // T_ADDRESS = 15, T_NARROWOOP, // T_NARROWOOP = 16, T_METADATA, // T_METADATA = 17, - T_CONFLICT // T_CONFLICT = 18, + T_NARROWKLASS, // T_NARROWKLASS = 18, + T_CONFLICT // T_CONFLICT = 19, }; int _type2aelembytes[T_CONFLICT+1] = { - 0, // 0 - 0, // 1 - 0, // 2 - 0, // 3 - T_BOOLEAN_aelem_bytes, // T_BOOLEAN = 4, - T_CHAR_aelem_bytes, // T_CHAR = 5, - T_FLOAT_aelem_bytes, // T_FLOAT = 6, - T_DOUBLE_aelem_bytes, // T_DOUBLE = 7, - T_BYTE_aelem_bytes, // T_BYTE = 8, - T_SHORT_aelem_bytes, // T_SHORT = 9, - T_INT_aelem_bytes, // T_INT = 10, - T_LONG_aelem_bytes, // T_LONG = 11, - T_OBJECT_aelem_bytes, // T_OBJECT = 12, - T_ARRAY_aelem_bytes, // T_ARRAY = 13, - 0, // T_VOID = 14, - T_OBJECT_aelem_bytes, // T_ADDRESS = 15, - T_NARROWOOP_aelem_bytes,// T_NARROWOOP= 16, - T_OBJECT_aelem_bytes, // T_METADATA = 17, - 0 // T_CONFLICT = 18, + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + T_BOOLEAN_aelem_bytes, // T_BOOLEAN = 4, + T_CHAR_aelem_bytes, // T_CHAR = 5, + T_FLOAT_aelem_bytes, // T_FLOAT = 6, + T_DOUBLE_aelem_bytes, // T_DOUBLE = 7, + T_BYTE_aelem_bytes, // T_BYTE = 8, + T_SHORT_aelem_bytes, // T_SHORT = 9, + T_INT_aelem_bytes, // T_INT = 10, + T_LONG_aelem_bytes, // T_LONG = 11, + T_OBJECT_aelem_bytes, // T_OBJECT = 12, + T_ARRAY_aelem_bytes, // T_ARRAY = 13, + 0, // T_VOID = 14, + T_OBJECT_aelem_bytes, // T_ADDRESS = 15, + T_NARROWOOP_aelem_bytes, // T_NARROWOOP= 16, + T_OBJECT_aelem_bytes, // T_METADATA = 17, + T_NARROWKLASS_aelem_bytes, // T_NARROWKLASS= 18, + 0 // T_CONFLICT = 19, }; #ifdef ASSERT --- old/src/share/vm/utilities/globalDefinitions.hpp 2012-10-08 20:37:03.509647843 +0200 +++ new/src/share/vm/utilities/globalDefinitions.hpp 2012-10-08 20:37:03.319207799 +0200 @@ -347,6 +347,14 @@ extern int LogMinObjAlignment; extern int LogMinObjAlignmentInBytes; +const int LogKlassAlignmentInBytes = 3; +const int LogKlassAlignment = LogKlassAlignmentInBytes - LogHeapWordSize; +const int KlassAlignmentInBytes = 1 << LogKlassAlignmentInBytes; +const int KlassAlignment = KlassAlignmentInBytes / HeapWordSize; + +// Klass encoding metaspace max size +const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes; + // Machine dependent stuff #ifdef TARGET_ARCH_x86 @@ -481,22 +489,23 @@ // NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/runtime/BasicType.java enum BasicType { - T_BOOLEAN = 4, - T_CHAR = 5, - T_FLOAT = 6, - T_DOUBLE = 7, - T_BYTE = 8, - T_SHORT = 9, - T_INT = 10, - T_LONG = 11, - T_OBJECT = 12, - T_ARRAY = 13, - T_VOID = 14, - T_ADDRESS = 15, - T_NARROWOOP= 16, - T_METADATA = 17, - T_CONFLICT = 18, // for stack value type with conflicting contents - T_ILLEGAL = 99 + T_BOOLEAN = 4, + T_CHAR = 5, + T_FLOAT = 6, + T_DOUBLE = 7, + T_BYTE = 8, + T_SHORT = 9, + T_INT = 10, + T_LONG = 11, + T_OBJECT = 12, + T_ARRAY = 13, + T_VOID = 14, + T_ADDRESS = 15, + T_NARROWOOP = 16, + T_METADATA = 17, + T_NARROWKLASS = 18, + T_CONFLICT = 19, // for stack value type with conflicting contents + T_ILLEGAL = 99 }; inline bool is_java_primitive(BasicType t) { @@ -544,18 +553,19 @@ // NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/runtime/BasicType.java enum BasicTypeSize { - T_BOOLEAN_size = 1, - T_CHAR_size = 1, - T_FLOAT_size = 1, - T_DOUBLE_size = 2, - T_BYTE_size = 1, - T_SHORT_size = 1, - T_INT_size = 1, - T_LONG_size = 2, - T_OBJECT_size = 1, - T_ARRAY_size = 1, - T_NARROWOOP_size = 1, - T_VOID_size = 0 + T_BOOLEAN_size = 1, + T_CHAR_size = 1, + T_FLOAT_size = 1, + T_DOUBLE_size = 2, + T_BYTE_size = 1, + T_SHORT_size = 1, + T_INT_size = 1, + T_LONG_size = 2, + T_OBJECT_size = 1, + T_ARRAY_size = 1, + T_NARROWOOP_size = 1, + T_NARROWKLASS_size = 1, + T_VOID_size = 0 }; @@ -567,23 +577,24 @@ // size in bytes enum ArrayElementSize { - T_BOOLEAN_aelem_bytes = 1, - T_CHAR_aelem_bytes = 2, - T_FLOAT_aelem_bytes = 4, - T_DOUBLE_aelem_bytes = 8, - T_BYTE_aelem_bytes = 1, - T_SHORT_aelem_bytes = 2, - T_INT_aelem_bytes = 4, - T_LONG_aelem_bytes = 8, + T_BOOLEAN_aelem_bytes = 1, + T_CHAR_aelem_bytes = 2, + T_FLOAT_aelem_bytes = 4, + T_DOUBLE_aelem_bytes = 8, + T_BYTE_aelem_bytes = 1, + T_SHORT_aelem_bytes = 2, + T_INT_aelem_bytes = 4, + T_LONG_aelem_bytes = 8, #ifdef _LP64 - T_OBJECT_aelem_bytes = 8, - T_ARRAY_aelem_bytes = 8, + T_OBJECT_aelem_bytes = 8, + T_ARRAY_aelem_bytes = 8, #else - T_OBJECT_aelem_bytes = 4, - T_ARRAY_aelem_bytes = 4, + T_OBJECT_aelem_bytes = 4, + T_ARRAY_aelem_bytes = 4, #endif - T_NARROWOOP_aelem_bytes = 4, - T_VOID_aelem_bytes = 0 + T_NARROWOOP_aelem_bytes = 4, + T_NARROWKLASS_aelem_bytes = 4, + T_VOID_aelem_bytes = 0 }; extern int _type2aelembytes[T_CONFLICT+1]; // maps a BasicType to nof bytes used by its array element --- /dev/null 2011-12-02 15:41:17.912098000 +0100 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java 2012-10-08 20:37:04.640309332 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.oops; + +import sun.jvm.hotspot.debugger.*; + +public class NarrowKlassField extends MetadataField { + + public NarrowKlassField(sun.jvm.hotspot.types.AddressField vmField, long startOffset) { + super(vmField, startOffset); + } + + public Metadata getValue(Address addr) { + return Metadata.instantiateWrapperFor(addr.getCompKlassAddressAt(getOffset())); + } + public void setValue(Oop obj, long value) throws MutationException { + // Fix this: set* missing in Address + } +}