changeset 3724:8e47bac5643a

7054512: Compress class pointers after perm gen removal Summary: support of compress class pointers in the compilers. Reviewed-by: kvn, twisti
author roland
date Tue, 09 Oct 2012 10:11:38 +0200
parents 65d07d9ee446
children f6badecb7ea7
files agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java agent/src/share/classes/sun/jvm/hotspot/oops/Array.java agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java agent/src/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java src/cpu/sparc/vm/assembler_sparc.cpp src/cpu/sparc/vm/assembler_sparc.hpp src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp src/cpu/sparc/vm/relocInfo_sparc.cpp src/cpu/sparc/vm/sparc.ad src/cpu/sparc/vm/vm_version_sparc.cpp src/cpu/sparc/vm/vtableStubs_sparc.cpp src/cpu/x86/vm/assembler_x86.cpp src/cpu/x86/vm/assembler_x86.hpp src/cpu/x86/vm/c1_FrameMap_x86.hpp src/cpu/x86/vm/c1_LIRAssembler_x86.cpp src/cpu/x86/vm/c1_LIRGenerator_x86.cpp src/cpu/x86/vm/c1_MacroAssembler_x86.cpp src/cpu/x86/vm/vtableStubs_x86_64.cpp src/cpu/x86/vm/x86_32.ad src/cpu/x86/vm/x86_64.ad src/os/bsd/dtrace/generateJvmOffsets.cpp src/os/bsd/dtrace/jhelper.d src/os/solaris/dtrace/generateJvmOffsets.cpp src/os/solaris/dtrace/jhelper.d src/share/vm/adlc/archDesc.cpp src/share/vm/adlc/forms.cpp src/share/vm/adlc/forms.hpp src/share/vm/adlc/formssel.cpp src/share/vm/adlc/output_c.cpp src/share/vm/adlc/output_h.cpp src/share/vm/c1/c1_LIRGenerator.cpp src/share/vm/ci/ciObjectFactory.cpp src/share/vm/classfile/classFileParser.cpp src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp src/share/vm/memory/metaspace.hpp src/share/vm/memory/universe.cpp src/share/vm/memory/universe.hpp src/share/vm/oops/instanceOop.hpp src/share/vm/oops/oop.inline.hpp src/share/vm/opto/cfgnode.cpp src/share/vm/opto/classes.hpp src/share/vm/opto/compile.cpp src/share/vm/opto/connode.cpp src/share/vm/opto/connode.hpp src/share/vm/opto/escape.cpp src/share/vm/opto/lcm.cpp src/share/vm/opto/library_call.cpp src/share/vm/opto/live.cpp src/share/vm/opto/loopTransform.cpp src/share/vm/opto/loopopts.cpp src/share/vm/opto/machnode.cpp src/share/vm/opto/macro.cpp src/share/vm/opto/matcher.cpp src/share/vm/opto/matcher.hpp src/share/vm/opto/memnode.cpp src/share/vm/opto/memnode.hpp src/share/vm/opto/node.hpp src/share/vm/opto/parse2.cpp src/share/vm/opto/subnode.cpp src/share/vm/opto/type.cpp src/share/vm/opto/type.hpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/stubRoutines.cpp src/share/vm/runtime/vmStructs.cpp src/share/vm/utilities/globalDefinitions.cpp src/share/vm/utilities/globalDefinitions.hpp
diffstat 93 files changed, 1603 insertions(+), 500 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java	Tue Oct 09 10:11:38 2012 +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
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java	Tue Oct 09 10:11:38 2012 +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;
+  }
 }
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java	Tue Oct 09 10:11:38 2012 +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);
 }
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java	Tue Oct 09 10:11:38 2012 +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
     //
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Tue Oct 09 10:11:38 2012 +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,
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java	Tue Oct 09 10:11:38 2012 +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
   //
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java	Tue Oct 09 10:11:38 2012 +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
     //
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Tue Oct 09 10:11:38 2012 +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,
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java	Tue Oct 09 10:11:38 2012 +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
   //
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	Tue Oct 09 10:11:38 2012 +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 {
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java	Tue Oct 09 10:11:38 2012 +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
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java	Tue Oct 09 10:11:38 2012 +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);
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java	Tue Oct 09 10:11:38 2012 +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);
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java	Tue Oct 09 10:11:38 2012 +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
   //
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java	Tue Oct 09 10:11:38 2012 +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;
 
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java	Tue Oct 09 10:11:38 2012 +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 {
--- a/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java	Tue Oct 09 10:11:38 2012 +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);
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java	Tue Oct 09 10:11:38 2012 +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;
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java	Tue Oct 09 10:11:38 2012 +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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java	Tue Oct 09 10:11:38 2012 +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
+  }
+}
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java	Tue Oct 09 10:11:38 2012 +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()));
     }
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java	Tue Oct 09 10:11:38 2012 +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 */
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Tue Oct 09 10:11:38 2012 +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() {
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java	Mon Oct 08 17:04:00 2012 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java	Tue Oct 09 10:11:38 2012 +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) {
--- a/src/cpu/sparc/vm/assembler_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp	Tue Oct 09 10:11:38 2012 +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);
   }
 }
--- a/src/cpu/sparc/vm/assembler_sparc.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp	Tue Oct 09 10:11:38 2012 +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);
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Tue Oct 09 10:11:38 2012 +0200
@@ -105,6 +105,11 @@
         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())) {
           return !PatchALot;
@@ -969,8 +974,19 @@
 #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 (offset == oopDesc::klass_offset_in_bytes()) {
+          __ lduw(base, offset, to_reg->as_register());
+#ifdef _LP64
+          if (UseCompressedKlassPointers) {
+            __ decode_klass_not_null(to_reg->as_register());
+          }
+#endif
+        } else {
+          __ ld_ptr(base, offset, to_reg->as_register());
+        }
+        break;
       case T_ARRAY : // fall through
       case T_OBJECT:
         {
@@ -2344,7 +2360,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);
--- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp	Tue Oct 09 10:11:38 2012 +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());
--- a/src/cpu/sparc/vm/relocInfo_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp	Tue Oct 09 10:11:38 2012 +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) {
--- a/src/cpu/sparc/vm/sparc.ad	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/sparc.ad	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/vm_version_sparc.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Tue Oct 09 10:11:38 2012 +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);
     }
   }
--- a/src/cpu/x86/vm/assembler_x86.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/assembler_x86.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/x86/vm/assembler_x86.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/assembler_x86.hpp	Tue Oct 09 10:11:38 2012 +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();
 
--- a/src/cpu/x86/vm/c1_FrameMap_x86.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/c1_FrameMap_x86.hpp	Tue Oct 09 10:11:38 2012 +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;
   }
 
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Tue Oct 09 10:11:38 2012 +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,12 @@
     }
 #endif
     __ verify_oop(dest->as_register());
+  } else if (type == T_ADDRESS && addr->disp() == oopDesc::klass_offset_in_bytes()) {
+#ifdef _LP64
+    if (UseCompressedKlassPointers) {
+      __ decode_klass_not_null(dest->as_register());
+    }
+#endif
   }
 }
 
@@ -1705,7 +1715,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 +3456,7 @@
     __ mov_metadata(tmp, default_type->constant_encoding());
 #ifdef _LP64
     if (UseCompressedKlassPointers) {
-      __ encode_heap_oop(tmp);
+      __ encode_klass_not_null(tmp);
     }
 #endif
 
--- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Tue Oct 09 10:11:38 2012 +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(),
--- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/x86/vm/x86_32.ad	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/x86_32.ad	Tue Oct 09 10:11:38 2012 +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
--- a/src/cpu/x86/vm/x86_64.ad	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/cpu/x86/vm/x86_64.ad	Tue Oct 09 10:11:38 2012 +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)" %}
--- a/src/os/bsd/dtrace/generateJvmOffsets.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/os/bsd/dtrace/generateJvmOffsets.cpp	Tue Oct 09 10:11:38 2012 +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));
--- a/src/os/bsd/dtrace/jhelper.d	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/os/bsd/dtrace/jhelper.d	Tue Oct 09 10:11:38 2012 +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);
 
--- a/src/os/solaris/dtrace/generateJvmOffsets.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/os/solaris/dtrace/generateJvmOffsets.cpp	Tue Oct 09 10:11:38 2012 +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));
--- a/src/os/solaris/dtrace/jhelper.d	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/os/solaris/dtrace/jhelper.d	Tue Oct 09 10:11:38 2012 +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);
 
--- a/src/share/vm/adlc/archDesc.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/archDesc.cpp	Tue Oct 09 10:11:38 2012 +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") ) {
--- a/src/share/vm/adlc/forms.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/forms.cpp	Tue Oct 09 10:11:38 2012 +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;
--- a/src/share/vm/adlc/forms.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/forms.hpp	Tue Oct 09 10:11:38 2012 +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;
--- a/src/share/vm/adlc/formssel.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/formssel.cpp	Tue Oct 09 10:11:38 2012 +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 ||
--- a/src/share/vm/adlc/output_c.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/output_c.cpp	Tue Oct 09 10:11:38 2012 +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) ) {
--- a/src/share/vm/adlc/output_h.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/adlc/output_h.cpp	Tue Oct 09 10:11:38 2012 +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: <TypePtr *>
           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:
--- a/src/share/vm/c1/c1_LIRGenerator.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Tue Oct 09 10:11:38 2012 +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);
 }
 
--- a/src/share/vm/ci/ciObjectFactory.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Tue Oct 09 10:11:38 2012 +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]);
     }
--- a/src/share/vm/classfile/classFileParser.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/classfile/classFileParser.cpp	Tue Oct 09 10:11:38 2012 +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) {
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Tue Oct 09 10:11:38 2012 +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");
--- a/src/share/vm/memory/metaspace.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/memory/metaspace.hpp	Tue Oct 09 10:11:38 2012 +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;
--- a/src/share/vm/memory/universe.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/memory/universe.cpp	Tue Oct 09 10:11:38 2012 +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();
     }
+    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());
   }
-  assert(Universe::narrow_oop_base() == (Universe::heap()->base() - os::vm_page_size()) ||
+  // 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;
 }
 
--- a/src/share/vm/memory/universe.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/memory/universe.hpp	Tue Oct 09 10:11:38 2012 +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,30 @@
   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)         {
+    _narrow_oop._shift   = shift;
+  }
+
+  static void     set_narrow_klass_shift(int shift)       {
+    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);
--- a/src/share/vm/oops/instanceOop.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/oops/instanceOop.hpp	Tue Oct 09 10:11:38 2012 +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);
   }
--- a/src/share/vm/oops/oop.inline.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/oops/oop.inline.hpp	Tue Oct 09 10:11:38 2012 +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;
 }
 
--- a/src/share/vm/opto/cfgnode.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/cfgnode.cpp	Tue Oct 09 10:11:38 2012 +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; i<req(); ++i) {// For all paths in
       Node *ii = in(i);
-      if (ii->is_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; i<req(); ++i) {// For all paths in
         Node *ii = in(i);
         Node* new_ii = NULL;
-        if (ii->is_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
--- a/src/share/vm/opto/classes.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/classes.hpp	Tue Oct 09 10:11:38 2012 +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)
--- a/src/share/vm/opto/compile.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/compile.cpp	Tue Oct 09 10:11:38 2012 +0200
@@ -2239,6 +2239,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 );
@@ -2287,6 +2288,7 @@
   case Op_GetAndSetN:
   case Op_StoreP:
   case Op_StoreN:
+  case Op_StoreNKlass:
   case Op_LoadB:
   case Op_LoadUB:
   case Op_LoadUS:
@@ -2321,7 +2323,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()) {
@@ -2330,16 +2332,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;
@@ -2348,7 +2352,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) {
@@ -2403,22 +2411,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.
@@ -2463,6 +2473,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) {
@@ -2479,23 +2491,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) {
@@ -2529,7 +2546,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);
@@ -2692,12 +2709,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();
@@ -2708,7 +2726,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?
--- a/src/share/vm/opto/connode.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/connode.cpp	Tue Oct 09 10:11:38 2012 +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 ) {
--- a/src/share/vm/opto/connode.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/connode.hpp	Tue Oct 09 10:11:38 2012 +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-------------------------------------
--- a/src/share/vm/opto/escape.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/escape.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/opto/lcm.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/lcm.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/opto/library_call.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/library_call.cpp	Tue Oct 09 10:11:38 2012 +0200
@@ -4383,7 +4383,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);
--- a/src/share/vm/opto/live.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/live.cpp	Tue Oct 09 10:11:38 2012 +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)) {
--- a/src/share/vm/opto/loopTransform.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/loopTransform.cpp	Tue Oct 09 10:11:38 2012 +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;
       }
--- a/src/share/vm/opto/loopopts.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/loopopts.cpp	Tue Oct 09 10:11:38 2012 +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);
         }
--- a/src/share/vm/opto/machnode.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/machnode.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/opto/macro.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/macro.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/opto/matcher.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/matcher.cpp	Tue Oct 09 10:11:38 2012 +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().
--- a/src/share/vm/opto/matcher.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/matcher.hpp	Tue Oct 09 10:11:38 2012 +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).
--- a/src/share/vm/opto/memnode.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/memnode.cpp	Tue Oct 09 10:11:38 2012 +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;
-
-  return phase->transform(new (phase->C) EncodePNode(x, t->make_narrowoop()));
+  if( t->isa_narrowklass()) return x;
+  assert (!t->isa_narrowoop(), "no narrow oop here");
+
+  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);
--- a/src/share/vm/opto/memnode.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/memnode.hpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/opto/node.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/node.hpp	Tue Oct 09 10:11:38 2012 +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)
--- a/src/share/vm/opto/parse2.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/parse2.cpp	Tue Oct 09 10:11:38 2012 +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 {
--- a/src/share/vm/opto/subnode.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/subnode.cpp	Tue Oct 09 10:11:38 2012 +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;
--- a/src/share/vm/opto/type.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/type.cpp	Tue Oct 09 10:11:38 2012 +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 TypeNarrowOop::eq( const Type *t ) const {
-  const TypeNarrowOop* tc = t->isa_narrowoop();
+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 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();
-}
-
-bool TypeNarrowOop::empty(void) const {
-  return _ptrtype->empty();
+const Type *TypeNarrowPtr::xdual() const {    // Compute dual right now.
+  const TypePtr* odual = _ptrtype->dual()->is_ptr();
+  return make_same_narrowptr(odual);
+}
+
+
+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?
 
-
-  // Current "this->_base" is OopPtr
+  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 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);
-}
-
-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;
-  }
-}
-
-
-intptr_t TypeNarrowOop::get_con() const {
-  return _ptrtype->get_con();
-}
+#ifndef PRODUCT
+void TypeNarrowPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
+  _ptrtype->dump2(d, depth, st);
+}
+#endif
+
+const TypeNarrowOop *TypeNarrowOop::BOTTOM;
+const TypeNarrowOop *TypeNarrowOop::NULL_PTR;
+
+
+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:
--- a/src/share/vm/opto/type.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/opto/type.hpp	Tue Oct 09 10:11:38 2012 +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
@@ -1153,19 +1164,89 @@
 
   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;
+
+#ifndef PRODUCT
+  virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
+#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) {
   }
 
-  static const TypeNarrowOop *BOTTOM;
-  static const TypeNarrowOop *NULL_PTR;
+  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;
@@ -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) )
--- a/src/share/vm/runtime/arguments.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Tue Oct 09 10:11:38 2012 +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)) {
--- a/src/share/vm/runtime/stubRoutines.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/runtime/stubRoutines.cpp	Tue Oct 09 10:11:38 2012 +0200
@@ -421,6 +421,7 @@
   case T_ARRAY:
   case T_OBJECT:
   case T_NARROWOOP:
+  case T_NARROWKLASS:
   case T_ADDRESS:
     // Currently unsupported
     return NULL;
--- a/src/share/vm/runtime/vmStructs.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Tue Oct 09 10:11:38 2012 +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)                                \
--- a/src/share/vm/utilities/globalDefinitions.cpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/utilities/globalDefinitions.cpp	Tue Oct 09 10:11:38 2012 +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
--- a/src/share/vm/utilities/globalDefinitions.hpp	Mon Oct 08 17:04:00 2012 -0700
+++ b/src/share/vm/utilities/globalDefinitions.hpp	Tue Oct 09 10:11:38 2012 +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